Skip to content

Commit da29a6b

Browse files
authored
📷 Add navigator.mediaDevices.getUserMedia API (#1077)
- [x] Allows camera access (implement `getUserMedia` API) - [x] `JSVal` -> `DOMRef` - [x] Re-export `JSVal` (convenience) - [x] Export `previousSibling`
1 parent 5f3b937 commit da29a6b

File tree

4 files changed

+80
-4
lines changed

4 files changed

+80
-4
lines changed

‎src/Miso.hs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ module Miso
7777
import Control.Monad (void)
7878
import Control.Monad.IO.Class (liftIO)
7979
import Data.IORef (newIORef)
80-
import Language.Javascript.JSaddle (Object(Object), JSM, JSVal)
80+
import Language.Javascript.JSaddle (Object(Object), JSM)
8181
#ifndef GHCJS_BOTH
8282
#ifdef WASM
8383
import qualified Language.Javascript.JSaddle.Wasm.TH as JSaddle.Wasm.TH
@@ -153,7 +153,7 @@ renderComponent
153153
-- ^ Name of the JS object that contains the drawing context
154154
-> Component model action
155155
-- ^ Component application
156-
-> JSM [JSVal]
156+
-> JSM [DOMRef]
157157
-- ^ Custom hook to perform any JSM action (e.g. render styles) before initialization.
158158
-> JSM ()
159159
renderComponent Nothing vcomp _ = startComponent vcomp
@@ -166,7 +166,7 @@ initComponent
166166
:: Eq model
167167
=> Component model action
168168
-- ^ Component application
169-
-> JSM [JSVal]
169+
-> JSM [DOMRef]
170170
-- ^ Custom hook to perform any JSM action (e.g. render styles) before initialization.
171171
-> JSM (ComponentState model action)
172172
initComponent vcomp@Component{..} hooks = do

‎src/Miso/FFI.hs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,15 @@ module Miso.FFI
4747
, getComponentId
4848
-- ** DOM
4949
, nextSibling
50+
, previousSibling
5051
-- ** Element
5152
, click
5253
, files
54+
-- ** Re-exports
55+
, JSVal
5356
) where
5457
-----------------------------------------------------------------------------
5558
import Miso.FFI.Internal
5659
-----------------------------------------------------------------------------
60+
import Language.Javascript.JSaddle (JSVal)
61+
-----------------------------------------------------------------------------

‎src/Miso/FFI/Internal.hs‎

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ module Miso.FFI.Internal
5555
, getElementById
5656
, diff
5757
, nextSibling
58+
, previousSibling
5859
-- * Conversions
5960
, integralToJSString
6061
, realFloatToJSString
@@ -99,6 +100,8 @@ module Miso.FFI.Internal
99100
-- * Element
100101
, files
101102
, click
103+
-- * Media
104+
, getUserMedia
102105
) where
103106
-----------------------------------------------------------------------------
104107
import Control.Concurrent (ThreadId, forkIO)
@@ -615,12 +618,18 @@ getParentComponentId domRef =
615618
getComponentId :: JSVal -> JSM Int
616619
getComponentId vtree = fromJSValUnchecked =<< vtree ! "componentId"
617620
-----------------------------------------------------------------------------
618-
-- | Fetch sibling DOM node
621+
-- | Fetch next sibling DOM node
619622
--
620623
-- @since 1.9.0.0
621624
nextSibling :: JSVal -> JSM JSVal
622625
nextSibling domRef = domRef ! "nextSibling"
623626
-----------------------------------------------------------------------------
627+
-- | Fetch previous sibling DOM node
628+
--
629+
-- @since 1.9.0.0
630+
previousSibling :: JSVal -> JSM JSVal
631+
previousSibling domRef = domRef ! "previousSibling"
632+
-----------------------------------------------------------------------------
624633
-- | When working with /<input>/ of type="file", this is useful for
625634
-- extracting out the selected files.
626635
--
@@ -645,3 +654,28 @@ files domRef = fromJSValUnchecked =<< domRef ! "files"
645654
click :: () -> JSVal -> JSM ()
646655
click () domRef = void $ domRef # "click" $ ([] :: [MisoString])
647656
-----------------------------------------------------------------------------
657+
-- | Get Camera on user's device
658+
--
659+
-- <https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia>
660+
--
661+
getUserMedia
662+
:: Bool
663+
-- ^ video
664+
-> Bool
665+
-- ^ audio
666+
-> (JSVal -> JSM ())
667+
-- ^ successful
668+
-> (JSVal -> JSM ())
669+
-- ^ errorful
670+
-> JSM ()
671+
getUserMedia video audio successful errorful = do
672+
params <- create
673+
set (ms "video") video params
674+
set (ms "audio") audio params
675+
devices <- jsg "navigator" ! "mediaDevices"
676+
promise <- devices # "getUserMedia" $ [params]
677+
successfulCallback <- asyncCallback1 successful
678+
void $ promise # "then" $ [successfulCallback]
679+
errorfulCallback <- asyncCallback1 errorful
680+
void $ promise # "catch" $ [errorfulCallback]
681+
-----------------------------------------------------------------------------

‎src/Miso/Media.hs‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
-----------------------------------------------------------------------------
2+
{-# LANGUAGE RecordWildCards #-}
23
{-# LANGUAGE OverloadedStrings #-}
34
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
45
-----------------------------------------------------------------------------
@@ -15,13 +16,17 @@ module Miso.Media
1516
Media (..)
1617
, NetworkState (..)
1718
, ReadyState (..)
19+
, UserMedia (..)
20+
, Stream
1821
-- *** Constructors
1922
, newAudio
23+
, userMedia
2024
-- *** Methods
2125
, canPlayType
2226
, load
2327
, play
2428
, pause
29+
, getUserMedia
2530
-- *** Properties
2631
, autoplay
2732
, controls
@@ -52,8 +57,10 @@ import Control.Monad
5257
import Language.Javascript.JSaddle hiding (new)
5358
import qualified Language.Javascript.JSaddle as JS
5459
-----------------------------------------------------------------------------
60+
import qualified Miso.FFI.Internal as FFI
5561
import Miso.FFI
5662
import Miso.Event
63+
import Miso.Effect
5764
import Miso.String
5865
-----------------------------------------------------------------------------
5966
newtype Media = Media JSVal
@@ -196,3 +203,33 @@ videoWidth (Media m) = fromJSValUnchecked =<< m ! ("videoWidth" :: MisoString)
196203
volume :: Media -> JSM Double
197204
volume (Media m) = fromJSValUnchecked =<< m ! ("volume" :: MisoString)
198205
-----------------------------------------------------------------------------
206+
-- | Type for dealing with 'navigator.mediaDevices.getUserMedia'
207+
data UserMedia
208+
= UserMedia
209+
{ audio, video :: Bool
210+
} deriving (Show, Eq)
211+
-----------------------------------------------------------------------------
212+
-- | Default 'UserMedia'
213+
userMedia :: UserMedia
214+
userMedia = UserMedia True True
215+
-----------------------------------------------------------------------------
216+
type Stream = JSVal
217+
-----------------------------------------------------------------------------
218+
-- | Get access to user's media devices.
219+
--
220+
-- <https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia>
221+
--
222+
getUserMedia
223+
:: UserMedia
224+
-- ^ Options
225+
-> (Stream -> action)
226+
-- ^ Successful callback
227+
-> (JSVal -> action)
228+
-- ^ Errorful callback
229+
-> Effect model action
230+
getUserMedia UserMedia {..} successful errorful =
231+
withSink $ \sink ->
232+
FFI.getUserMedia audio video
233+
(sink . successful)
234+
(sink . errorful)
235+
-----------------------------------------------------------------------------

0 commit comments

Comments
 (0)