Skip to content

Instantly share code, notes, and snippets.

@danabrams
Created January 25, 2019 14:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danabrams/8b986556e7b534f2ad4993988f6977f0 to your computer and use it in GitHub Desktop.
Save danabrams/8b986556e7b534f2ad4993988f6977f0 to your computer and use it in GitHub Desktop.
About the simplest possible Audio Player example for my Elm Media Control API
module AudioPlayer exposing (main)
import Browser
import Html exposing (..)
import Html.Events exposing (onClick)
import Media exposing (Setting(..), Source(..), changeSetting)
import Result exposing (Result(..))
import Task exposing (Task)
type Msg
= CreatedMedia (Result Media.Error Media.Id)
| StateUpdated Media.State
| SettingChanged (Result Media.Error Media.State)
| ClickedPause
| ClickedPlay
type alias Model =
{ media : Maybe Media.Id, currentTime : Maybe Float }
main =
Browser.element { init = init, update = update, subscriptions = subscriptions, view = view }
init () =
( { media = Nothing, currentTime = Nothing }
, Task.attempt CreatedMedia <|
Media.create
{ sources = [ Url "https://mySite.com/myFile.mp3" ]
, loop = False
, autoplay = False
, muted = False
, volume = Nothing
}
)
subscriptions : Model -> Sub Msg
subscriptions model =
case model.media of
Just mediaId ->
Media.state StateUpdated mediaId
Nothing ->
Sub.none
update msg model =
case msg of
CreatedMedia result ->
case result of
Ok mediaId ->
( { model | media = Just mediaId }, Cmd.none )
Err _ ->
( model, Cmd.none )
SettingChanged result ->
case result of
Ok mediaState ->
( { model | currentTime = Just mediaState.currentTime }, Cmd.none )
Err _ ->
( model, Cmd.none )
StateUpdated mediaState ->
( { model | currentTime = Just mediaState.currentTime }, Cmd.none )
ClickedPlay ->
case model.media of
Just mediaId ->
( model, Task.attempt SettingChanged <| changeSettings mediaId Play )
Nothing ->
( model, Cmd.none )
ClickedPause ->
case model.media of
Just mediaId ->
( model, Task.attempt SettingChanged <| changeSetting mediaId Pause )
Nothing ->
( model, Cmd.none )
view model =
let
status =
case model.currentTime of
Nothing ->
"No Media"
Just ct ->
"Current Time: " ++ String.fromFloat ct
in
div []
[ text status
, button [ onClick ClickedPlay ] [ text "Play" ]
, button [ onClick ClickedPause ] [ text "Pause" ]
]
module Media exposing
( Id, create, Config, Source(..), state, State, Error
, changeSetting, Setting(..)
, video
)
{-|
# Media
@docs Id, create, Config, Source, state, State, Error, TimeRange
# Settings
@docs changeSetting, Setting
# Dom
@docs video
-}
import Html exposing (Attribute, Html)
import Task exposing (Task)
{-| Create a new piece of media that you can then play or otherwise manipulate.
-}
create : Config -> Task Error Id
create =
Debug.todo "create media not implemented"
{-| Change a setting on your media, like changing the Volume or Pausing it.
-}
changeSetting : Id -> Setting -> Task Error State
changeSetting mediaId =
Debug.todo "setState not implemented"
{-| A subscription to the current State of your media. NOTE: In final implementation, we'll probably need to make a "WithOptions" version for some advanced use-cases.
-}
state : (State -> msg) -> Id -> Sub msg
state mediaId msg =
Debug.todo "media state subscription not yet implemented"
{-| Create a visible Html Dom node using your video Id.
-}
video : Id -> List (Html attribute) -> Html msg
video mediaId attrs =
Debug.todo "video function not implemented"
{-| This is the key type. It stores a reference to your media that you pass to the Tasks in this package. You need to create it before you can do anything.
-}
type Id
= Id Int
{-| A work in progress enumeration of all the possible errors
-}
type Error
= InvalidSetting
| InvalidSource
| SettingAgainstBrowserPolicy
| NetworkConnectivity
{-| An example of what a State record might look like
-}
type alias State =
{ currentTime : Float
, duration : Float
, playback : Playback
, source : Source
, loop : Bool
, muted : Bool
, volume : Int
, buffered : List TimeRange
, seekable : List TimeRange
, played : List TimeRange
, textTracks : List String
}
{-| A time range is a range of time withing the media, for instance, 0:03 to 0:15.
-}
type alias TimeRange =
{ start : Float, end : Float }
{-| Current status of media playback
-}
type Playback
= Playing
| Paused
| Ended
| PlaybackError String
{-| Where is the media file you want to play. In the future, we can add other source types, like webcams, or webRTC video chats, etc.
-}
type Source
= Url String
{-| This is how you configure your media when you create it. It takes a list of sources because best practice to include fallback versions using different codecs. NOTE: You would probably also define things like TextTracks (subtitles) in here.
-}
type alias Config =
{ sources : List Source
, loop : Bool
, autoplay : Bool
, muted : Bool
, volume : Maybe Float
}
{-| These are the settings you can (attempt to) change the state of media. NOTE: This is a simple set, there are some more dealing with things like TextTracks, but I think these give the idea.
-}
type Setting
= Play
| Pause
| Seek Float
| SetSource Source
| Mute
| Unmute
| SetVolume Int
| Loop
| NoLoop
| Autoplay
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment