$ = jQuery context = window logger = context.JK.logger rest = context.JK.Rest() EVENTS = context.JK.EVENTS BrowserMediaActions = @BrowserMediaActions Howler._enableiOSAudio() @BrowserMediaStore = Reflux.createStore( { listenables: BrowserMediaActions audio: null loaded: false loading: false playing: false paused: false load_error: false id: null media_type: null cachedAudio: [] cache_size: 10 preload: true playbackState:(position, time) -> state = {} if @playing state.playbackState = 'play_start' else if @paused state.playbackState = 'play_pause' else state.playbackState = 'play_stop' state.playbackStateChanged = !@state? || @state.isPlaying != @playing || @state.paused != @paused state.positionUpdateChanged = !@state? || @state.positionMs != position state.currentTimeChanged = !@state? || @state.time != time state changed: () -> position = @onGetPlayPosition() time = context.JK.prettyPrintSeconds(parseInt(position / 1000)) playbackState = @playbackState(position, time) # XXX: how to deal with duration? no mention in Howler API target = {id: @id, isPlaying: @playing, loaded: @loaded, paused: @paused, loading: @loading, load_error: @load_error, positionMs: position, time: time, durationMs: @onGetPlayDuration()} $.extend(true, target, playbackState) @state = target @trigger(@state) onLoad: (id, urls, media_type) -> if @loading logger.error("you can't switch to different audio while loading due to weird errors seen in Howler") window.location.reload() return if @audio @audio.stop() @loaded = false @loading = false @playing = false @paused = false @load_error = false @audio = null @id = id @media_type = media_type @loading = @preload @playing = false @paused = false for cacheItem in @cachedAudio if cacheItem.id == id # items in our own cache are only there if we saw that it fully loaded @audio = cacheItem.audio @loaded = true @loading = false unless @audio? @audio = new Howl({ src: urls, autoplay: false, loop: false, volume: 1, preload: @preload, onend: @onAudioEnded, onload: @onAudioLoaded, onloaderror: @onAudioLoadError, onpause: @onAudioPause, onplay: @onAudioPlay }) @audio.jkid = id @changed() onPlay: () -> logger.debug("BrowerMediaStore:play") if @audio @playing = true @paused = false @audio.play() try if !@audio.recorded_play rest.postUserEvent({name: @media_type + '_play'}) if @media_type? context.stats.write('web.' + @media_type + '.play', { value: 1, user_id: context.JK.currentUserId, user_name: context.JK.currentUserName }) if @media_type @audio.recorded_play = true catch e logger.warn("BrowserMediaStore: unable to post user event") onPause: () -> if @audio @playing = false @paused = true @audio.pause() onStop: () -> if @audio @playing = false @paused = false try @audio.pause() catch e @logger.info("unable to pause on stop", e) try @audio.seek(0) catch e @logger.info("unable to seek to beginning on stop", e) onSeek: (pos) -> if @audio console.log("seek time", pos) @audio.seek(pos / 1000) onGetPlayPosition: () -> if @audio try position = @audio.seek() if position == @audio return 0 position * 1000 catch e return 0 else 0 onGetPlayDuration: () -> if @audio # XXX : how to determine duration? try duration = @audio.duration() return Math.round(duration) * 1000 catch e return 0 else 0 onAudioEnded: () -> logger.debug("onAudioEnded") @playing = false @changed() onAudioLoaded: () -> logger.debug("onAudioLoaded", arguments) @loaded = true @loading = false # add audio to cache, and ageout cached audio items if more than 10 \ if @cachedAudio.length >= @cache_size audio = @cachedAudio.shift() try audio.audio.unload() catch e logger.error("unable to unload aged audio", @audio) @cachedAudio.push({id: @audio.jkid, audio: @audio}) @changed() onAudioLoadError: () -> logger.debug("onAudioLoadError", arguments) @load_error = true @loading = false @changed() onAudioPause: () -> logger.debug("onAudioPause") @changed() onAudioPlay: () -> logger.debug("onAudioPlay") @playing = true @paused = false @changed() } )