hey savonet developers!

Regarding the way predicates for the switch operator behaves, I'm still 
a bit confused. It's a follow up to the attached message, located at the 
end of the mail.

Consider the following simple example (see below) - mkqueuedynamic() is 
embedded within a fallback node not displayed here, I would have 
expected each switch predicate to be evaluated once either of the switch 
source is over but it's not the case, the switch predicates are only 
'visited' during initialization and never ever after, I'm still missing 
something to properly understand how it works.
Here's how I thought the following snippet was working:
when a source is needed, each predicate of the switch is sequentially 
'visited', if one switch case returns true the associated method is 
called, if none is true, we exit mkqueuedynamic().
In the first switch predicate, check_new_track() calls a webservice to 
fill in some metadata that then point to ref_item_meta.
check_new_track() and check_blank() check if some variable is set in the 
value of ref_item_meta, if it's the case the associated method, 
play_track() or play_blank(), respectively, is called.
Once the source created by either of these methods is over (end of track 
for play_track() or sine() reaching its manually set duration for 
play_blank()), the switch predicates are then re-evaluated.

# Create a Shampoo source
def mkqueuedynamic(_id, _ws_key) =

        #Set during instantiation
        ref_item_meta = ref [("error", "1")]

        def is_blank(m) =
log("***is_blank? "^m["type"])
                m["type"] == "blank"
        end
        
        def check_new_track() =
                log("check_new_track()")
                
                #What to play next?
                item_meta = get_shampoo_nextitem(_id, _ws_key)
                ref_item_meta := item_meta

log("***check_new_track=="^string_of(not(is_blank(item_meta))))
                not(is_blank(item_meta))
        end

        def check_blank() =
                log("check_blank()")
                item_meta = !ref_item_meta

                is_blank(item_meta)
        end

        def play_blank() =
                log("play_blank()")
                item_meta = !ref_item_meta

                sine(duration=float_of_string(item_meta["liq_cue_out"]))
        end

        def play_track() =
                log("play_track()")
                item_meta = !ref_item_meta

                def make_request() =
log("***request.create("^item_meta['item_url_endpoint']^")")
                        request.create(item_meta["item_url_endpoint"])
                end
log("***request.dynamic(make_request)")
                request.dynamic(make_request)
        end
        
        source = switch(
                id="queue_"^_id,
                track_sensitive=true,
                transitions=[fallback_transition, fallback_transition],
                [
                        #Play a new requested track
                        (check_new_track, play_track()),
                        #Play an 'end of programme' signal
                        (check_blank, play_blank())
                ]
        )
...

Here's the associated log, as you can see play_track() and play_blank() 
are both visited whereas check_new_track() AND check_blank() return 
false (I've double checked what the webservice returns.) And I would 
have expected everything to be sequentially displayed in the logs, at 
least the switch predicates print() outputs to be displayed BEFORE the 
switch main methods'. Maybe it's because lots of threads are used but 
why aren't the switch predicates and main methods called within the same 
one in this case? Or is it a problem with unflushed I/O streams? Harder 
to debug in this case with log() and print() only. Anyway, the log 
output really puzzles me.
And the fact the make_request() just stupidly loops without any chance 
to abort the procedure...
Note: 'Nonexistent file or ill-formed URI ""!' is normal, the 
"item_url_endpoint" metadata is not properly filled in by the webservice 
on purpose.


2011/08/22 01:27:22 >>> LOG START
2011/08/22 01:27:21 [protocols.external:3] Didn't find "ufetch".
2011/08/22 01:27:21 [protocols.external:3] Didn't find "wget".
2011/08/22 01:27:21 [main:3] Liquidsoap 1.0.0-beta3+svn 
(default@83addd3ddbae:20110820:143301)
2011/08/22 01:27:21 [main:3] Using: graphics=[distributed with Ocaml] 
pcre=6.1.0 dtools=0.2.2 duppy=0.4.1 duppy.syntax=0.4.1 cry=0.2.1 
mm=0.1.0 ogg=0.4.2 vorbis=0.6.0 mad=0.4.3 flac=0.1.0 flac.ogg=0.1.0 
dynlink=[distributed with Ocaml] lame=0.3.0 samplerate=0.1.1 
taglib=0.1.4 magic=0.7.3 camomile=0.8.1 faad=0.3.0 ladspa=0.1.3 
json-wheel=1.0.6
2011/08/22 01:27:21 [main:2]
2011/08/22 01:27:21 [main:2] DISCLAIMER: This version of Liquidsoap has been
2011/08/22 01:27:21 [main:2] compiled from a snapshot of the development 
code.
2011/08/22 01:27:21 [main:2] As such, it should not be used in production
2011/08/22 01:27:21 [main:2] unless you know what you are doing!
2011/08/22 01:27:21 [main:2]
2011/08/22 01:27:21 [main:2] We are, however, very interested in any 
feedback
2011/08/22 01:27:21 [main:2] about our development code and committed to fix
2011/08/22 01:27:21 [main:2] issues as soon as possible.
2011/08/22 01:27:21 [main:2]
2011/08/22 01:27:21 [main:2] If you are interested in collaborating to
2011/08/22 01:27:21 [main:2] the development of Liquidsoap, feel free to
2011/08/22 01:27:21 [main:2] drop us a mail at <[email protected]>
2011/08/22 01:27:21 [main:2] or to join the #savonet IRC channel on 
Freenode.
2011/08/22 01:27:21 [main:2]
2011/08/22 01:27:21 [main:2] Please send any bug report or feature request
2011/08/22 01:27:21 [main:2] at <http://dev.sourcefabric.org/browse/LS>.
2011/08/22 01:27:21 [main:2]
2011/08/22 01:27:21 [main:2] We hope you enjoy this snapshot build of 
Liquidsoap!
2011/08/22 01:27:21 [main:2]
2011/08/22 01:27:21 [lang:3] Lastfm/audioscrobbler support was not compiled.
2011/08/22 01:27:21 [frame:3] Using 44100Hz audio, 25Hz video, 44100Hz 
master.
2011/08/22 01:27:21 [frame:3] Frame size must be a multiple of 1764 
ticks = 1764 audio samples = 1 video samples.
2011/08/22 01:27:21 [frame:3] Targetting 'frame.duration': 0.04s = 1764 
audio samples = 1764 ticks.
2011/08/22 01:27:21 [frame:3] Frames last 0.04s = 1764 audio samples = 1 
video samples = 1764 ticks.
2011/08/22 01:27:21 [lang:3] reloading channel list
2011/08/22 01:27:21 [lang:3] streaming channel channel1
2011/08/22 01:27:21 [lang:3] shampoo_ws_getter()
2011/08/22 01:27:22 [lang:3] play_track()
2011/08/22 01:27:22 [lang:3] ***request.dynamic(make_request)
2011/08/22 01:27:22 [lang:3] play_blank()
2011/08/22 01:27:22 [lang:3] done
2011/08/22 01:27:22 [threads:3] Created thread "generic queue #1".
2011/08/22 01:27:22 [harbor:3] Adding mountpoint '/' on port 8030
2011/08/22 01:27:22 [BACKUP(dot)txt:3] Loading playlist...
2011/08/22 01:27:22 [BACKUP(dot)txt:3] Playlist treated as format 
audio/mpegurl
2011/08/22 01:27:22 [lang:3] ***request.create()
2011/08/22 01:27:22 [decoder:3] Method "MP3" accepted "/tmp/My 
Music/LABEL/DDC_R_/CITY_OF_/02___LOG.MP3".
2011/08/22 01:27:22 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:22 [decoder:3] Method "MP3" accepted "/tmp/My 
Music/LABEL/DDC_R_/CITY_OF_/03___LOG.MP3".
2011/08/22 01:27:22 [lang:3] ***request.create()
2011/08/22 01:27:22 [decoder:3] Method "MP3" accepted "/tmp/My 
Music/LABEL/DDC_R_/WRISTBLA/02___JAZ.MP3".
2011/08/22 01:27:22 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:22 [decoder:3] Method "MP3" accepted "/tmp/My 
Music/LABEL/DDC_R_/O/03___REA.MP3".
2011/08/22 01:27:22 [lang:3] ***request.create()
2011/08/22 01:27:22 [decoder:3] Method "MP3" accepted "/tmp/My 
Music/LABEL/DDC_R_/LAST_IN_/08___THE.MP3".
2011/08/22 01:27:22 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:22 [decoder:3] Method "MP3" accepted "/tmp/My 
Music/LABEL/DDC_R_/LAST_IN_/07___50_.MP3".
2011/08/22 01:27:22 [BACKUP(dot)txt:3] Successfully loaded a playlist of 
6 tracks.
2011/08/22 01:27:22 [lang:3] ***request.create()
2011/08/22 01:27:22 [lang:3] check_new_track()
2011/08/22 01:27:22 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:22 [lang:3] shampoo_ws_getter()
2011/08/22 01:27:23 [lang:3] ***is_blank? blank
2011/08/22 01:27:23 [lang:3] ***check_new_track==false
2011/08/22 01:27:23 [lang:3] ***is_blank? blank
2011/08/22 01:27:23 [lang:3] check_blank()
2011/08/22 01:27:23 [lang:3] ***is_blank? blank
2011/08/22 01:27:23 [/test:3] Connecting mount /test for [email protected]...
2011/08/22 01:27:23 [/test:3] Connection setup was successful.
2011/08/22 01:27:23 [lang:3] bootup channel channel1
2011/08/22 01:27:23 [lang:3] shampoo_ws_setter()
2011/08/22 01:27:24 [threads:3] Created thread "wallclock_main" (1 total).
2011/08/22 01:27:24 [clock.wallclock_main:3] Streaming loop starts, 
synchronized with wallclock.
2011/08/22 01:27:24 [fallback_5048:3] Switch to src_5044.
2011/08/22 01:27:24 [queue_channel1:3] Switch to sine_5032.
2011/08/22 01:27:24 [src_5034:3] Inserting missing metadata.
2011/08/22 01:27:24 [lang:3] map_metadata()
2011/08/22 01:27:24 [cue_cut_5035:2] Ignoring negative cue-in point.
2011/08/22 01:27:24 [lang:3] item_start_feedback()
2011/08/22 01:27:24 [lang:3] shampoo_ws_setter()
2011/08/22 01:27:24 [lang:3] ***request.create()
2011/08/22 01:27:24 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:24 [lang:3] ***request.create()
2011/08/22 01:27:24 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:24 [lang:3] ***request.create()
2011/08/22 01:27:24 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:24 [lang:3] ***request.create()
2011/08/22 01:27:24 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:26 [lang:3] ***request.create()
2011/08/22 01:27:26 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:26 [lang:3] ***request.create()
2011/08/22 01:27:26 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:26 [lang:3] ***request.create()
2011/08/22 01:27:26 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:26 [lang:3] ***request.create()
2011/08/22 01:27:26 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:28 [lang:3] ***request.create()
2011/08/22 01:27:28 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:28 [lang:3] ***request.create()
2011/08/22 01:27:28 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:28 [lang:3] ***request.create()
2011/08/22 01:27:28 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:28 [lang:3] ***request.create()
2011/08/22 01:27:28 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:30 [lang:3] ***request.create()
2011/08/22 01:27:30 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:30 [lang:3] ***request.create()
2011/08/22 01:27:30 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:30 [lang:3] ***request.create()
2011/08/22 01:27:30 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:30 [lang:3] ***request.create()
2011/08/22 01:27:30 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:32 [lang:3] ***request.create()
2011/08/22 01:27:32 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:32 [lang:3] ***request.create()
2011/08/22 01:27:32 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:32 [lang:3] ***request.create()
2011/08/22 01:27:32 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:32 [lang:3] ***request.create()
2011/08/22 01:27:32 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:34 [lang:3] ***request.create()
2011/08/22 01:27:34 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:34 [lang:3] ***request.create()
2011/08/22 01:27:34 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:34 [lang:3] ***request.create()
2011/08/22 01:27:34 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:34 [lang:3] ***request.create()
2011/08/22 01:27:34 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:36 [lang:3] ***request.create()
2011/08/22 01:27:36 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:36 [lang:3] ***request.create()
2011/08/22 01:27:36 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:36 [lang:3] ***request.create()
2011/08/22 01:27:36 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:36 [lang:3] ***request.create()
2011/08/22 01:27:36 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:38 [lang:3] ***request.create()
2011/08/22 01:27:38 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:38 [lang:3] ***request.create()
2011/08/22 01:27:38 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:38 [lang:3] ***request.create()
2011/08/22 01:27:38 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:38 [lang:3] ***request.create()
2011/08/22 01:27:38 [request:3] Nonexistent file or ill-formed URI ""!
2011/08/22 01:27:38 [main:3] Shutdown started!
2011/08/22 01:27:38 [main:3] Waiting for threads to terminate...
2011/08/22 01:27:38 [/test:3] Closing connection...
2011/08/22 01:27:38 [lang:3] shutdown channel channel1
2011/08/22 01:27:38 [lang:3] shampoo_ws_setter()
2011/08/22 01:27:39 [harbor:3] Removing mountpoint '/' on port 8030
2011/08/22 01:27:39 [harbor:3] Nothing more on port 8030: closing sockets.
2011/08/22 01:27:39 [clock.wallclock_main:3] Streaming loop stopped.
2011/08/22 01:27:39 [threads:3] Thread "wallclock_main" terminated (0 
remaining).
2011/08/22 01:27:39 [main:3] Cleaning downloaded files...
2011/08/22 01:27:39 >>> LOG END


Can you please explain to me what I obviously didn't understand?
But I now see why everybody uses telnet to program the streams though :) 
Anyway, I've got a kludge (sort of) to make it work without any switch 
but it's incredibly ugly, limited, bug-prone, and long (400 lines.)

Thank you.

On 08/08/2011 02:30, Romain Beauxis wrote:
> 2011/8/7 okay_awright<[email protected]>:
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA1
>>
>> Hello Romain.
>
> Hi!
>
>> I'm really sorry, my description was clear as mud.
>>
>> - From what I understand, the procedure/function for each "case" of the
>> switch is evaluated during intialization (I read in the doc that once
>> the script is parsed, the graph is built and related objects are
>> created, and you call that instantiation I think.) The outcome of the
>> predicates is settled at that time - except when we deal with
>> time-related operators I think. I just came to this conclusion using
>> printf() and markers within test scripts. I'm maybe wrong though. Please
>> correct me.
>>
>> Anyway, what I'd love to get are "case" functions that are 'visited'
>> each time a branch of the switch must be selected - a real dynamic
>> operator, where case predicates are evaluated each time the switch
>> operates. It's like the regular switch, except that the "cases" behave
>> more like 'event' triggers (like on_track(), on_end(), on_connect(), etc.)
>>
>> Myabe I'm mistaken and the original switch doesn't really behave the way
>> I've described. Please tell me if there's a solution/workaround/whatever
>> to make the switch act like a true dynamic operator.
>
> Actually the predicates in the different branches of the switch are
> evaluated dynamically :-)
> Each of them is a function of type: () ->  bool, i.e. a function that
> takes no parameter and returns true if the source ought to be played..
>
> What must be confusing is the notation: { 1h-4h }. This notation is a
> shortcut for:
> def predicate() =
>    1h-4h
> end
>
> More generally, { foo } is a shortcut for the function: () ->  foo..
>
> In any case, the predicates are evaluated regularly. You may use for
> them any function of your choice. This I believe the switch does
> behave the way you want :-)
>
> Romain

-- 
best regards,

okay_awright
<okay_awright AT ddcr DOT biz>
[PGP key on request]

------------------------------------------------------------------------------
Get a FREE DOWNLOAD! and learn more about uberSVN rich system, 
user administration capabilities and model configuration. Take 
the hassle out of deploying and managing Subversion and the 
tools developers use with it. http://p.sf.net/sfu/wandisco-d2d-2
_______________________________________________
Savonet-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/savonet-users

Reply via email to