GSoC:2008/GenIPC
From XMMS2
| Student: | Leonid Evdokimov | Current milestone: | Student accepted | |
| Mentor: | Anders Waldenborg | Next milestone: | [clientlib] | |
| client library code generator that should ease consistent API definition. | ||||
That's temporary place to unload mess from the brain to.
Contents |
Q & A
Primitives that are NOT generated
- Low-level IPC that knows nothing about XMMS2
- connect(URL), that should register itself within mainloop too
- buffered(?) write
- reading bytes and sending them to upper layer, it's GenIPC work to split stream into packets
- forcing disconnection
- Serialization to basic types:
- «int32» and «uint32» — should be sent in network-byte order
- «string» — should be sent in UTF-8 encoding
- «data» — some set of bytes that should fit in memory, sending DVD images over XMMS2 is not the best idea
Will be legacy API generated?
NO, it makes things too low-level.
Protocol changes
Right now every message sent to server looks like:
| data | meaning |
|---|---|
| Type of Object ID | Reserved integer, almost like IANA's TCP ports. |
| Method ID | Another hardcoded integer |
| Object ID | Playlist name, collection name, medialib entry id |
| payload | some weird bytes |
Well, that's cool, but RESERVED NUMBERS?!
Why am I against reserved numbers? That's easy, XML does not have numbers inside, any text description does not have any reserved numbers inside.
Adding reserved numbers to text description makes things worse, they need maintaining, they should preserve compatibility. Reserved number should be generated and all we have are names of "class", "method" and/or "property". Reserved number should remain persistent in case of reordering entries in XML file.
Destroying reserved numbers and replacing reserved numbers with reserved words makes service clients more natural.
Should it be possible to register two instances of same "service client" in case of name collision?
No, only one client should do actual work, other clients should listen for an event about the work done, though spying function calls MAY be useful.
There are two major types of Xmms2 objects that are manipulated with API: Singleton/Monostate objects (like "stats" or "medialib") and "numerous" objects, e.g. playlists or collections that have some identifier attached.
It should be possible to apply any function to any numerous object, e.g. it should be possible to shuffle stored playlist (well, xmms2d may return "non implemented" error at first).
Limiting expressions for numeric properties
LOGICAL_EXP: 'NOT' LOGICAL_EXP
| LOGICAL_EXP "AND" LOGICAL_EXP
| LOGICAL_EXP "OR" LOGICAL_EXP
| '(' LOGICAL_EXP ')'
| 'TRUE'
| 'FALSE'
| MATH_EXP '<' MATH_EXP
| MATH_EXP '>' MATH_EXP
| MATH_EXP '<=' MATH_EXP
| MATH_EXP '>=' MATH_EXP
| MATH_EXP '==' MATH_EXP
MATH_EXP: 'actual_value'
| 'actual_time'
| 'last_sent_value'
| 'last_sent_time'
| '(' MATH_EXP ')'
| NUMERIC
| MATH_EXP '+' MATH_EXP
| MATH_EXP '-' MATH_EXP
| MATH_EXP '*' MATH_EXP
| MATH_EXP '/' MATH_EXP
NUMERIC: /* some integer or floating number */
I hope, nobody wants "sin" and "log".
Maybe I should use BC as a library?
Object properties
Property manipulation functions, every function returns new value:
- numerical:
- type add(type X)
- type sub(type X)
- type set(type X)
- type get()
- list<T>:
- int length
watchable, is numerical property
- int length
- map<K, V>:
- list<K> keys
Changing sub-value (e.g. map<K, V>[k] = new_v) fires watch functions attached to container. For example, that makes possible to watch either all config key-value pairs or only equaliser-related ones.
Evey watch function may have some LOGICAL_EXP's attached, every function may
introduce time-related limits, function watching numerical types can also
attach value-related limits.
FIXME: review grammar to limit possible expressions. It's bad idea
to recheck expression during every iteration, time-related expressions
should be convertable to timers, value-related expressions can be checked
on value modification.
Playlists
Static methods:
- list<string> list()
-
string current()
it becomes impossible to have two playback streams with different playlist - void create(string name)
Object methods:
- void ->destroy()
- void ->shuffle()
- void ->insert(binstring url, bool recursive = false, int pos = -1)
non-encoded URL should be given - void ->insert(int track_id, int pos = -1)
WTF: that's just a helper, it creates idlist internally - void ->insert(collection idlist, int pos = -1)
- void ->insert(collection coll, list<string> order, int pos = -1)
- void ->erase(int position)
- void ->clear()
- void ->sort(list<string> order)
- void ->move(int old_pos, int new_pos)
- void ->load()
Object's data members:
- int ->position
- list<int> ->tracklist
readonly
xmmsc_result_t *xmmsc_broadcast_playlist_changed (xmmsc_connection_t *c); xmmsc_result_t *xmmsc_broadcast_playlist_current_pos (xmmsc_connection_t *c);
watching Playlist(name)->tracklist, Playlist(name)->position
xmmsc_result_t *xmmsc_broadcast_playlist_loaded (xmmsc_connection_t *c);
is moved to Playback(name)->playlist
Playback
Types:
- enumeration status { PLAY, STOP, PAUSE }
Static methods:
- void create(string name)
Static data members:
- list<string> ->list
Object's data members:
- enumeration status ->status
status.set(PLAY) while playing ~= tickle(), i.e. forcing decoding the song atPlaylist(this->playlist).position - string ->playlist
- int ->timestamp_ms
- int ->timestamp_samples
- map<string, int> ->volume
volume.keys is immutable - int ->current_id
readonly
it's used to show the track that is REALLY playing, e.g. current playlist and playlist position could be changed while the track is playing, but playing new track was not enforced, so it's stored here
xmmsc_result_t *xmmsc_broadcast_playback_volume_changed (xmmsc_connection_t *c); xmmsc_result_t *xmmsc_broadcast_playback_status (xmmsc_connection_t *c); xmmsc_result_t *xmmsc_signal_playback_playtime (xmmsc_connection_t *c); xmmsc_result_t *xmmsc_broadcast_playback_current_id (xmmsc_connection_t *c);
watching Playback(name)->volume[channel], Playback(name)->timestamp_ms, Playback(name)->status, Playback(name)->current_id
Config
Static methods:
- void register(string key, string default_value)
Static data members:
- map<string, string> value
xmmsc_result_t *xmmsc_broadcast_configval_changed (xmmsc_connection_t *c);
Stats
Medialib
Static methods:
- string entry_format(property_dict)
- void add(binstring url, bool recursive = false)
non-encoded URL should be given - property_dict get_info(int id)
- void rehash(int id = 0)
- int get_id(binstring url)
- void erase(int id)
- void rename(int id, binstring url)
- void property_set(int id, string key, int value)
- void property_set(int id, string source, string key, int value)
- void property_set(int id, string key, string value)
- void property_set(int id, string source, string key, string value)
- void property_remove(int id, string key)
- void property_remove(int id, string source, string key)
xmmsc_result_t *xmmsc_broadcast_medialib_entry_changed (xmmsc_connection_t *c); xmmsc_result_t *xmmsc_broadcast_medialib_entry_added (xmmsc_connection_t *c);
source defaults to "client/${CLIENT_NAME}"
XForm
Types:
- dict dentry { path: string, isdir: bool, realpath?: string, ... }
Static methods:
- list<dentry> browse(binstring url)
Bindata
Static methods:
- string add(binstring buffer)
- void remove(string hash)
Static data members:
- list<string> keys
readonly - binstring data[string keys]
readonly

