#!/usr/local/bin/python
# records a stream of bytes from stdin, inserting timing marks.
# Format is as follows:
# "%c%d:%s," where %c is a character, %d is an integer, %s is a string
# of length %d, is a record; note that this is a character plus one of
# Dan Bernstein's "netstrings".  Three types of records are defined:
#   when %c is 's', it's a string that was received.
#   when %c is 'e', it's an EOF, and the string is empty.
#   when %c is 't', it's a timestamp, and the string is a decimal number:
#     the number of seconds since start of recording.
#   when %c is 'c', it's a comment.
#   Playback programs are supposed to ignore records they don't recognize the
#   tags of.
# This program can't handle more than about nine megabytes per second on my
# laptop.

import sys, time, select, fcntl, FCNTL

def write_rec(code, content=''):
    assert len(code) == 1 and type(code) is type('s')
    sys.stdout.write("%s%d:%s," % (code, len(content), content))
    sys.stdout.flush()

def record_stream(precision=0.1):
    """Record a stream of bytes with timing information.

    precision specifies how precise to make the recording.

    """
    write_rec('c', ("Movie made with Kragen Sitaker's record-movie.\n" +
    "See http://www.pobox.com/~kragen/sw/movie/ for more info.\n" +
    "This movie made at %(time)s\nwith %(version)s."
    ) % {'time': (time.asctime(time.localtime(time.time())) +
                  " %s/%s" % time.tzname),
         'version': "Python %s on a %s system" % (sys.version,
                                                  sys.platform)})
    infd = 0
    old_stdin_mode = fcntl.fcntl(infd, FCNTL.F_GETFL) 
    fcntl.fcntl(infd, FCNTL.F_SETFL, old_stdin_mode | FCNTL.O_NONBLOCK)
    start = time.time()
    last_recorded_time = start
    while 1:
        r, w, x = select.select([infd], [], [], None)
        if not infd in r: continue
        now = time.time()
        if now > last_recorded_time + precision:
            reltime = now - start + precision / 2.0
            write_rec('t', "%.1f" % (reltime - reltime % precision))
            last_recorded_time = now
        try: string = sys.stdin.read(4096)
        except IOError, error:
            errnum, errmsg = error#.args
            if errnum == 0:  # this is a bug in Python
                string = ""
            else:    # XXX handle EAGAIN?
                raise
        if string == '':
            write_rec('e')
            fcntl.fcntl(infd, FCNTL.F_SETFL, old_stdin_mode)
            return
        else:
            write_rec('s', string)

if __name__ == "__main__": record_stream()
