ZERO = datetime.timedelta(0)
(MARK_NUMBER, MARK_BOOL, MARK_STRING, MARK_OBJECT, MARK_MOVIECLIP, MARK_NULL,
 MARK_UNDEFINED, MARK_REFERENCE, MARK_ECMA_ARRAY, MARK_OBJECT_END,
 MARK_STRICT_ARRAY, MARK_DATE, MARK_LONG_STRING, MARK_UNSUPPORTED,
 MARK_RECORDSET, MARK_XML_DOCUMENT, MARK_TYPED_OBJECT,
 MARK_AVMPLUS_OBJECT) = range(0x12)
class UTC(datetime.tzinfo):
class OrderedDict(DictMixin, object):
class OrderedObject(OrderedDict):
class DecoderError(ValueError):
class EncoderError(ValueError):
class UndefinedType(object):
class Object(OrderedObject):
class Reference(object):
class ECMAArray(OrderedDict):
class XMLDocument(unicode):
    def utcoffset(self, dt):
    def tzname(self, dt):
    def dst(self, dt):
    def __init__(self, other=None, **kw):
    def __getitem__(self, key):
    def __setitem__(self, key, value):
    def __delitem__(self, key):
    def __iter__(self):
    def __contains__(self, key):
    def __len__(self):
        def __hash__(self):
    def keys(self):
    def iteritems(self):
    def copy(self):
    def __repr__(self):
    def __init__(self, other=None, **kw):
    def __getattr__(self, name):
    def __setattr__(self, name, value):
    def __delattr__(self, name):
    def copy(self):
    def s(self, **kw):
    def __repr__(self):
    def __eq__(self, other):
    def __ne__(self, other):
    def __hash__(self):
    def __repr__(self):
    def __init__(self, index):
    def __eq__(self, other):
    def __ne__(self, other):
    def __hash__(self):
    def __repr__(self):
def _decode_marker(s):
def _decode_number(s):
def _decode_boolean(s):
def _decode_any_string(s, unpacker):
def _decode_string(s):
def _decode_object_like(s, setter):
def _decode_object(s):
def _decode_null(s):
def _decode_undefined(s):
def _decode_reference(s):
def _decode_ecma_array(s):
def _decode_strict_array(s):
def _decode_date(s):
def _decode_long_string(s):
def _decode_xml_document(s):
def _decode_typed_object(s):
def _decode_unsupported(s):
def _decode_single(s, type_dict=decoders):
def _decode(s, type_dict=decoders):
def _encode_number(s, value):
def _encode_boolean(s, value):
def _encode_string(s, value):
def _encode_unicode(s, value):
def _encode_null(s, _value):
def _encode_undefined(s, _value):
def _encode_reference(s, value):
def _encode_strict_array(s, value):
def _encode_date(s, value):
def _encode_xml_document(s, value):
def _encode_property_name(s, value):
def _encode_object_like_content(s, value):
def _encode_ecma_array(s, value):
def _encode_object(s, value):
def _encode_single(s, value, type_dict=encoders):
def _encode(s, values, type_dict=encoders):
def _encode_variable_name(s, name):
def decode(data):
def decode_one(data):
def encode(*args):
def decode_variable(data):
def encode_variable(name, value): class Header(object):
class ChunkStreamParseError(ValueError):
class ChunkStreamValueError(ValueError):
class Demuxer(object):
class Chunker(object):
class SimpleChunkProducer(object):
class Muxer(object):
    def __init__(self, cs_id, time, size, type, ms_id, **kw):
    def __repr__(self):
        def _repr_maybe(v, provided):
def absolutize(h, base):
def read_header_head(s):
    def __init__(self, protocol):
    def doSetChunkSize(self, header, new_size):
    def doAbortMessage(self, header, cs_id):
    def doACK(self, header, seq_num):
    def doUserControlMessage(self, header, evt_type, body):
    def doWindowSize(self, header, window_size):
    def doSetBandwidth(self, header, window_size, limit_type):
    def controlMessageUnknown(self, header, body):
    def controlMessageReceived(self, header, body):
    def gen_handler(self):
def _encode_basic_header(h_type, cs_id, time=None):
def encode_full_header(cs_id, time, size, msg_type, ms_id):
def encode_comp_header(h_type, cs_id, time, size, msg_type, ms_id):
    def set_chunk_size(self, new_chunk_size):
    def __call__(self, cs_id, first_header, body, time=None):
    def __init__(self, transport):
    def queue_chunker(self, priority, chunker):
    def sync(self, priority):
    def pauseProducing(self):
    def resumeProducing(self):
    def stopProducing(self):
    def __init__(self, transport):
    def _precompute_dispatch(self, amf_ver):
    def _make_adhoc_csid(self, mt):
    def set_chunk_size(self, new_chunk_size):
    def sendMessage(self, time, type_, ms_id, body, absolute=False):
DEFAULT_CHUNK_SIZE = 128
(PROTO_SET_CHUNK_SIZE, PROTO_ABORT_MESSAGE, PROTO_ACK, PROTO_USER_CONTROL,
 PROTO_WINDOW_SIZE, PROTO_SET_BANDWIDTH, MSG_COMMAND, MSG_DATA, MSG_SO,
 MSG_AUDIO, MSG_VIDEO, MSG_AGGREGATE) = range(12) class ProtocolContractError(ValueError):
    pass class UnexpectedStatusError(ValueError):
    pass class CommandResultError(RuntimeError):
    def __str__(self):
        desc = None
        if (self.args and len(self.args) == 2 and
            isinstance(self.args[1], amf0.Object)):
            obj = self.args[1]
            if obj.has_key('description'):
                desc = '%s: %s' % (obj.get('code', self.__class__.__name__),
                                   obj.description)
        return desc or RuntimeError.__str__(self) class CallResultError(ValueError):
    """Call resulted in an error"""

    level = 'error'
    code = 'NetStream.Failed'   # looks like the most generic error type code

    def __init__(self, *args, **kwargs):
        ValueError.__init__(self, *args)
        self.is_fatal = kwargs.get('fatal', False)

    def get_error_args(self):
        dsc = self.__doc__
        if self.args:
            dsc = '%s: %s' % (dsc, self.args[0])
        return (None, amf0.Object(level=self.level, code=self.code,
                                  description=dsc)) class CallAbortedException(Exception):
    """Call aborted""" class DispatchProtocol(BaseProtocol):
    demuxer_class = UserControlDispatchDemuxer

    def __init__(self):
        BaseProtocol.__init__(self)

        self.msg_dispatch = None

        self.bytes_read = 0 # all bytes received minus headers (?)
        self._next_ack = 0
        self.window_size = 2500000

        self.set_next_ack()

        self.build_message_dispatch()

    def set_window_size(self, new_size):
        if new_size != self.window_size:
            old_size, self.window_size = self.window_size, new_size
            self.set_next_ack(old_size)
            self.check_send_ack()

    def set_next_ack(self, old_window_size=0):
        # the actual "algorithm" is here - Adobe's software seems to send
        # acks after _half_ the window size...
        old_ack_inc = int(old_window_size / 2)
        ack_inc = int(self.window_size / 2)
        self._next_ack += ack_inc - old_ack_inc

    def check_send_ack(self):
        if self._next_ack < self.bytes_read:
            self.set_next_ack()
            self.muxer.sendMessage(0, chunks.PROTO_ACK, 0,
                                   vb(_s_ulong.pack(self.bytes_read)))

    def bytes_received(self, count):
        self.bytes_read += count
        self.check_send_ack()

    def build_message_dispatch(self):
        # for now we only support AMF0

        def amf_args(header, body):
            return header.abs_time, header.ms_id, amf0.decode(body)
        def data_args(header, body):
            return header.type, header.abs_time, header.ms_id, body

        # { type => (handler, make_args) }
        self.msg_dispatch = {
            const.RTMP_AUDIO: (self.doData, data_args),
            const.RTMP_VIDEO: (self.doData, data_args),
            const.RTMP_DATA: (self.doMeta, amf_args),
            const.RTMP_COMMAND: (self.doCommand, amf_args),
            }

    def messageReceived(self, header, body):
        entry = self.msg_dispatch.get(header.type, None)
        if not entry:
            self.unknownMessageType(header, body)
            return

        handler, make_args = entry

        args = make_args(header, body)
        handler(*args)

    def unknownMessageType(self, header, body):
        pass

    def doCommand(self, ts, ms_id, args):
        pass

    def doMeta(self, ts, ms_id, args):
        pass

    def doData(self, type_, ts, ms_id, body):
        pass

    def connectionLost(self, reason=protocol.connectionDone):
        self._cc_queue.cancel_all()
        BaseProtocol.connectionLost(self, reason) class DispatchFactory(BaseFactory):
    protocol = DispatchProtocol def ms_time_wrapped(t):
    """Convert time t from (real) seconds to (int) milliseconds and
    wrap it to [0; 0xffffffff] range."""

    return ms_time(t) % 0x100000000
from collections import deque
from twisted.internet import protocol
from twisted.internet import defer, reactor
from twisted.python import failure
from twimp import amf0
from twimp import chunks
from twimp.error import ProtocolContractError, UnexpectedStatusError
from twimp.error import CommandResultError
from twimp.error import CallResultError, CallAbortedException
from twimp.proto import DispatchProtocol, DispatchFactory
from twimp.utils import ms_time_wrapped
import logging
import time
import twimp.log
        # track_id > 0 -> will return a tracking deferred
        d = None

        if track_id:
            d = defer.Deferred()
            self._call_tracker.push_deferred(ms_id, track_id, d)

        self.muxer.sendMessage(0, chunks.MSG_COMMAND, ms_id, body)
        return d

    def _sendRemote(self, ms_id, cmd, args, kwargs, track):
        # ignoring kwargs for now...
        trans_id = 0
        if track:
            trans_id = self._call_tracker.next_trans(ms_id)
        encoded_args = self.encode_amf(cmd, trans_id, *args)

        # hardcoding 0 time, does not seem to matter much...
        return self._send_command(0, ms_id, encoded_args, trans_id)

    def callRemote(self, ms_id, cmd, *args, **kw):
        return self._sendRemote(ms_id, cmd, args, kw, True)

    def signalRemote(self, ms_id, cmd, *args, **kw):
        # similar to callRemote, except we don't expect any results
        return self._sendRemote(ms_id, cmd, args, kw, False)


class CommandDispatchFactory(DispatchFactory):
    protocol = CommandDispatchProtocol


class EventDispatchProtocol(CommandDispatchProtocol):
    def __init__(self):
        CommandDispatchProtocol.__init__(self)

        self._events = StatusEventTracker()

    def _onStatus_ev_key(self, ms_id):
        return (None, ms_id)

    def waitStatus(self, ms_id, code):
        return self._events.wait(self._onStatus_ev_key(ms_id), code)

    def command_onStatus(self, ts, ms_id, _trans_id, _none, info):
        # trans_id not used, and _none seems to always be None...

        def miss_handler():
            self.unhandledOnStatus(ts, ms_id, info)

        self._events.dispatch(self._onStatus_ev_key(ms_id), info,
                              miss_h=miss_handler)

    def unhandledOnStatus(self, ts, ms_id, info):
        log.warning('unhandled onStatus: at %r, stream %r, info: %r',
                    ts, ms_id, info)

    def connectionLost(self, reason=protocol.connectionDone):
        self._events.cancel_all(reason=reason)

        CommandDispatchProtocol.connectionLost(self, reason)


class EventDispatchFactory(CommandDispatchFactory):
    protocol = EventDispatchProtocol


class CallDispatchProtocol(EventDispatchProtocol):
    def __init__(self):
        EventDispatchProtocol.__init__(self)

    def session_time(self):
        return time.time() - self.session_init_time

    def unknownCommandType(self, cmd, ts, ms_id, args):
        trans_id = args[0]

        handler_m = getattr(self, 'remote_%s' % (cmd,), None)

        if handler_m is None:
            d = defer.maybeDeferred(self.unknownRemoteCall, cmd, ts, ms_id,
                                    args[1:])
        else:
            d = defer.maybeDeferred(handler_m, ts, ms_id, *args[1:])

        if trans_id:
            d.addCallback(self._remote_handler_cb, ms_id, trans_id)

        d.addErrback(self._remote_abort_handler_eb)
        d.addErrback(self._remote_handler_eb, ms_id, trans_id)

    def _remote_abort_handler_eb(self, failure):
        failure.trap(CallAbortedException)
        # log failure but do nothing more
        log.debug('remote call aborted: %s', failure.value)

    def _remote_handler_cb(self, result, ms_id, trans_id):
        # log.debug('remote call result: %r', result)
        if not isinstance(result, (tuple, list)):
            result = (result,)

        body = self.encode_amf('_result', trans_id, *result)

        ts = ms_time_wrapped(self.session_time())
        self.muxer.sendMessage(ts, chunks.MSG_COMMAND, ms_id, body)

    def _remote_handler_eb(self, failure, ms_id, trans_id):
        if log.isEnabledFor(logging.DEBUG):
            log.info('remote call failure: %s', failure.value,
                     exc_info=(failure.type, failure.value,
                               failure.getTracebackObject()))
        else:
            log.info('remote call failure: %s', failure.value)

        fatal = False
        if failure.check(CallResultError):
            body = self.encode_amf('_error', trans_id,
                                   *failure.value.get_error_args())
            fatal = failure.value.is_fatal
        else:

            err = amf0.Object(code='NetStream.Failed', level='error',