speakd
Documentation
Login

Introduction

speakd polls a priority queue (stored on disk as an SQLite database) for events and, in priority order (with time order used to break priority ties), handles them by following per-event rules.

The rules are arbitrary Scheme code that accept any parameters stored with the event in the queue, and generate a sequence of actions. The available actions are text-to-speech (using espeak) in English or Lojban, playing .wav files, playing .ogg files (via ogg123), playing .mp3 files (via mpg123), and pausing for a specified length of time.

speakd will daemonise itself, and will read a file called speakd.handlers from the current directory to find the event handlers. The file is reloaded when it changes, so you don't need to restart speakd.

speakd-event will insert an event into the queue.

speakd

speakd [-D] [-d <db-path>] [-c <handlers-path>]

Runs the speakd daemon.

If -D is specified, it will not daemonize, but remain in the foreground and deliver diagnostics to standard output.

If -d is specified, a custom path to the queue database can be given. Otherwise, the default is /tmp/speakd.sqlite.

If -c is specified, a custom path to the handler file can be given. Otherwise, the default is speakd.handlers in the current directory.

speakd-event

speakd-event [-p <priority>] [-d <db-path>] <event>

Inserts an event into the queue.

If -d is specified, a custom path to the queue database can be given. Otherwise, the default is /tmp/speakd.sqlite.

If -p is specified, then the numeric priority will be applied to the event. Otherwise, the default priority is 0. The priority may be negative to make it lower than the default, or positive to make it higher.

The event must be a valid Scheme s-expression, and it must be a list whose first element is a symbol specifying the type of event, and any other elements must be the appropriate arguments for that event type.

speakd.handlers

The speakd.handlers file contains a list of event types, and the code to handle them. The handlers are arbitrary Chicken Scheme code, so don't trust third-party handler files without inspecting them!

The file is read and evaluated to produce an alist mapping event type symbols to handler functions, so you will probably want to create it using a quasiquotation, like so:

`(
(test
 . ,(lambda ()
        '((text-jbo ".i cipra")
          (pause 2)
          (text-en "Test")
          (nop)
          (jingle-ogg "test.ogg")
          (jingle-wav "test.wav")
          (jingle-mp3 "test.mpg")))
)

The handler function must accept any event parameters as arguments; this example provides only a single event type, test, that takes no arguments, so would be invoked as (test).

It must return a list of actions. Each action is itself a list, resembling a Scheme procedure application; the first element is a symbol specifying the type of action, and the rest are arguments.

The legal actions are:

(text-en string...)

Concatenates the string argument(s) into one string, and speaks them via an English text-to-speech engine.

(text-jbo string...)

Concatenates the string argument(s) into one string, and speaks them via a Lojban text-to-speech engine.

(jingle-[ogg|wav|mp3] filename)

Plays the contents of the specified OGG, WAV or MP3 file. The current working directory is left untouched when speakd starts, so paths can be relative to that.

(pause duration)

Pauses for the specified duration, in seconds.

(nop)

Does nothing. This is useful as a dummy for making actions conditional, like so: (if greeting '(text-en "Hello") '(nop)).

Parameters to events can be easily utilised to customise actions. For instance:

`((time
   . ,(lambda (hour)
        `((text-jbo ".i li " ,(number->string hour) " tcika")
          (text-en "It's " ,(number->string hour) " o'clock"))))
)

Failing handlers

If a handler fails, it will be retried up to ten times, then it will remain in the queue but be ignored. The failure error message will be stored in the queue alongside it.

This can currently be inspected by manually opening the queue file with sqlite:

chicken-sqlite /tmp/speakd.sqlite 'select * from queue'

However, I should provide a way of dealing with them. Perhaps repeatedly-failed handlers should be turned into (handler-failure ...) events?

Future Directions

TODO