Open ianffcs opened 4 months ago
some remarks:
StreamBuilder
in a sample but rather :watch
(see my example bellow):let [pipe-state (some-> audio-player
.-playbackEventStream
^#/(da/Stream as/PlaybackState) (.map (fn [a] (prn 'CACA) (transform-event a)))
(.pipe (.-playbackState as-handler)))
_add-item-to-audio-handler (.add (.-mediaItem as-handler) media-item)
_set-audio-source-to-media-id (.setAudioSource audio-player (-> media-item
.-id
Uri/parse
ja/AudioSource.uri))
media-stream (rx/Rx.combineLatest2 (.-mediaItem as-handler)
(as/AudioService.position)
(fn [^as/MediaItem media-item
^Duration position]
{:media-item media-item
:position position}))]
in a let
it's going to be rebuild every time smth changes - for combineLatest
, I might take time to develop smth here.
I've not finished the work, I am quite busy but it's a start
(ns sample.audio-service
"Sample definided inside audio_service package on:
https://github.com/ryanheise/audio_service/blob/minor/audio_service/example/lib/example_android13.dart"
(:require ["package:flutter/material.dart" :as m]
["package:flutter/widgets.dart" :as w]
["package:audio_service/audio_service.dart" :as as]
["package:just_audio/just_audio.dart" :as ja]
["package:rxdart/rxdart.dart" :as rx]
["common.dart" :as c]
["dart:async" :as da]
[cljd.flutter :as f]))
(def ^as/MediaItem media-item
(as/MediaItem
.id "https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3"
.album "Science Friday",
.title "A Salute To Head-Scratching Science"
.artist "Science Friday and WNYC Studios"
.duration (Duration .milliseconds 5739820)
.artUri (Uri/parse "https://media.wnyc.org/i/1400/1400/l/80/1/ScienceFriday_WNYCStudios_1400.jpg")))
(deftype MyAudioHandler [^ja/AudioPlayer audio-player]
:extends (as/BaseAudioHandler)
(play [_]
(.play audio-player))
(pause [_]
(.pause audio-player))
(stop [_]
(.stop audio-player))
^:mixin as/SeekHandler
(seek [_ ^Duration duration]
(.seek audio-player duration)))
(defn ^:async main []
(.ensureInitialized w/WidgetsFlutterBinding)
(f/run
(m/MaterialApp .title "Welcome to Flutter")
.home
(m/Scaffold .appBar (m/AppBar .title (m/Text "Welcome to ClojureDart")))
.body
m/Center
:managed [audio-player (ja/AudioPlayer)]
:let [transform-event
(fn [^ja/PlaybackEvent event]
(as/PlaybackState
.controls [as/MediaControl.rewind
(if (some-> audio-player .-playing)
as/MediaControl.pause
as/MediaControl.play)
as/MediaControl.stop
as/MediaControl.fastForward]
.systemActions #{as/MediaAction.seek
as/MediaAction.seekForward
as/MediaAction.seekBackward}
.androidCompactActionIndices [0 1 3]
.processingState (get {ja/ProcessingState.idle as/AudioProcessingState.idle
ja/ProcessingState.loading as/AudioProcessingState.loading
ja/ProcessingState.buffering as/AudioProcessingState.buffering
ja/ProcessingState.ready as/AudioProcessingState.ready
ja/ProcessingState.completed as/AudioProcessingState.completed}
(some-> audio-player
.-processingState))
.playing (-> audio-player
.-playing)
.updatePosition (-> audio-player .-position)
.bufferedPosition (-> audio-player .-bufferedPosition)
.speed (-> audio-player .-speed)
.queueIndex (-> event .-currentIndex)))]
:watch [^MyAudioHandler? as-handler (as/AudioService.init
.builder (fn [] ^as/AudioHandler (->MyAudioHandler ^ja/AudioPlayer audio-player))
.config (as/AudioServiceConfig
.androidNotificationChannelId "sample.audioService"
.androidNotificationChannelName "Sample Audio Service"
.androidNotificationOngoing true
.androidShowNotificationBadge true)) :dispose nil]
:when as-handler
:let [pipe-state (some-> audio-player
.-playbackEventStream
^#/(da/Stream as/PlaybackState) (.map (fn [a] (prn 'CACA) (transform-event a)))
(.pipe (.-playbackState as-handler)))
_add-item-to-audio-handler (.add (.-mediaItem as-handler) media-item)
_set-audio-source-to-media-id (.setAudioSource audio-player (-> media-item
.-id
Uri/parse
ja/AudioSource.uri))
media-stream (rx/Rx.combineLatest2 (.-mediaItem as-handler)
(as/AudioService.position)
(fn [^as/MediaItem media-item
^Duration position]
{:media-item media-item
:position position}))]
:when audio-player
(m/Column .mainAxisAlignment m/MainAxisAlignment.center)
.children
[(f/widget
:watch [media-item (.-mediaItem as-handler)]
:when media-item
(m/Text (.-title ^as/MediaItem media-item)))
(f/widget
:watch [playback-state (.-playbackState as-handler) #_(stream (map dedupe) (.-playbackState as-handler))]
:let [playing (some-> playback-state .-playing)]
(m/Row .mainAxisAlignment m/MainAxisAlignment.center)
.children
[(m/IconButton
.icon (m/Icon m/Icons.fast_rewind)
.iconSize 64
.onPressed (fn [] (.rewind ^MyAudioHandler as-handler) nil))
(m/IconButton
.icon (m/Icon (if playing m/Icons.pause m/Icons.play_arrow))
.iconSize 64
.onPressed (fn []
(if playing
(.pause ^MyAudioHandler as-handler)
(.play ^MyAudioHandler as-handler))
nil))
(m/IconButton
.icon (m/Icon m/Icons.stop)
.iconSize 64
.onPressed (fn []
(.stop ^MyAudioHandler as-handler)
nil))
(m/IconButton
.icon (m/Icon m/Icons.fast_forward)
.iconSize 64
.onPressed (fn []
(.fastForward ^MyAudioHandler as-handler)
nil))])
(f/widget
:watch [ms media-stream]
:when ms
(c/SeekBar
.duration (or (some-> ^as/MediaItem (get ms :media-item) .-duration) Duration/zero)
.position (or (some-> ms :position) Duration/zero)
.onChangeEnd (fn [new-pos]
(.seek ^as/SeekHandler as-handler new-pos)
nil)))
(f/widget
:watch [ps (some-> ^as/AudioHandler as-handler
.-playbackState
(.map (fn [st]
(.-playing ^as/PlaybackState st)))
(.distinct))]
(m/Text (str "Processing state: " (or ps as/AudioProcessingState.idle))))]))
Hey @ianffcs thank you for this work. However I think it's better for samples to focus on one thing at a time so that the reader doesn't have to grok several concepts/libs at once. Here several unrelated packages are used. Would it be possible to reduce the scope?
I can't think on how I can reduce the scope, because it's a sample about having an audio player that plays on background. This is the minimal example that I've found around for doing this.
This is very useful for anyone that wants to implement this audio-background feature in any app.
Audio Service sample reflecting this example: https://github.com/ryanheise/audio_service/blob/minor/audio_service/example/lib/example_android13.dart