Exemple #1
0
class ProducingChannel(BaseChannel):
    """
    Writes RTMP frames.

    @ivar buffer: Any data waiting to be written to the underlying stream.
    @type buffer: L{BufferedByteStream}
    @ivar acquired: Whether this channel is acquired. See L{ChannelMuxer.
        acquireChannel}
    """


    def __init__(self, channelId, stream, frameSize):
        BaseChannel.__init__(self, channelId, stream, frameSize)

        self.buffer = BufferedByteStream()
        self.acquired = False
        self.callback = None


    def setCallback(self, cb):
        """
        Sets the callback that will be fired once this channel has been completely
        encoded.
        """
        self.callback = cb


    def reset(self):
        """
        Called when the channel has completed writing the buffer.
        """
        BaseChannel.reset(self)

        self.buffer.seek(0)
        self.buffer.truncate()
        self.header = None


    def append(self, data):
        """
        Appends data to the buffer in preparation of encoding in RTMP.
        """
        self.buffer.append(data)


    def marshallFrame(self, size):
        """
        Writes a section of the buffer as part of the RTMP frame.
        """
        self.stream.write(self.buffer.read(size))
Exemple #2
0
class ProducingChannel(BaseChannel):
    """
    Writes RTMP frames.

    @ivar buffer: Any data waiting to be written to the underlying stream.
    @type buffer: L{BufferedByteStream}
    @ivar acquired: Whether this channel is acquired. See L{ChannelMuxer.
        acquireChannel}
    """


    def __init__(self, channelId, stream, frameSize):
        BaseChannel.__init__(self, channelId, stream, frameSize)

        self.buffer = BufferedByteStream()
        self.acquired = False
        self.callback = None


    def setCallback(self, cb):
        """
        Sets the callback that will be fired once this channel has been completely
        encoded.
        """
        self.callback = cb


    def reset(self):
        """
        Called when the channel has completed writing the buffer.
        """
        BaseChannel.reset(self)

        self.buffer.seek(0)
        self.buffer.truncate()
        self.header = None


    def append(self, data):
        """
        Appends data to the buffer in preparation of encoding in RTMP.
        """
        self.buffer.append(data)


    def marshallFrame(self, size):
        """
        Writes a section of the buffer as part of the RTMP frame.
        """
        self.stream.write(self.buffer.read(size))
Exemple #3
0
class BaseStreamer(object):
    """
    Provides all the base functionality for handling an RTMP input/output.

    @ivar decoder: RTMP Decoder that is fed data via L{dataReceived}
    """

    implements(message.IMessageListener)

    dispatcher = MessageDispatcher


    @property
    def decoding(self):
        """
        Whether this streamer is currently decoding RTMP message/s.

        If all the input buffer has been consumed, this will be C{False}.
        """
        return getattr(self, 'decoding_task', None) is not None


    @property
    def encoding(self):
        """
        Whether this streamer is currently encoding RTMP message/s.
        """
        return getattr(self, 'encoding_task', None) is not None


    def getWriter(self):
        """
        Returns a file like object that provides a I{write} method. This must be
        provided by subclasses.

        For example, for L{protocol.Protocol} instances this should return
        C{self.transport}.
        """
        raise NotImplementedError


    def buildStreamManager(self):
        """
        Returns an instance that provides L{interfaces.IStreamManager}. This
        must be provided by subclasses.
        """
        raise NotImplementedError


    def getDispatcher(self):
        """
        Returns an instance that will provide L{interfaces.IMessageDispatcher}
        """
        return self.dispatcher(self)


    def bytesInterval(self, bytes):
        """
        """
        self.sendMessage(message.BytesRead(bytes), self.controlStream)


    def startStreaming(self):
        """
        This must be called before any RTMP data is received.
        """
        self.streamManager = self.buildStreamManager()
        self.controlStream = self.streamManager.getControlStream()

        self._decodingBuffer = BufferedByteStream()
        self._encodingBuffer = BufferedByteStream()

        self.decoder = codec.Decoder(self.getDispatcher(), self.streamManager,
            stream=self._decodingBuffer)
        self.encoder = codec.Encoder(self.getWriter(),
            stream=self._encodingBuffer)

        self.decoder_task = None
        self.encoder_task = None


    def stopStreaming(self, reason=None):
        """
        """
        self.streamManager.closeAllStreams()

        self._decodingBuffer.truncate()
        self._encodingBuffer.truncate()

        del self._decodingBuffer
        del self._encodingBuffer

        del self.decoder_task, self.decoder
        del self.encoder_task, self.encoder


    def dataReceived(self, data):
        """
        Data has been received by the endpoint.
        """
        self.decoder.send(data)

        if not self.decoding:
            self.startDecoding()


    def startDecoding(self):
        """
        Called to start the decoding process.

        @return: A C{Deferred} which will kill the task once the decoding is
            done or on error.
        """
        def cullTask(result):
            self.decoder_task = None

            return result

        self.decoder_task = task.coiterate(self.decoder)

        self.decoder_task.addBoth(cullTask)

        return self.decoder_task


    def startEncoding(self):
        """
        Called to start asynchronously iterate the encoder.

        @return: A C{Deferred} which will kill the task once the encoder is
            done or on error will kill the connection.
        @todo: See _startDecoding todo. The same applies here.
        """
        def cullTask(result):
            self.encoder_task = None

            return result

        self.encoder_task = task.coiterate(self.encoder)

        self.encoder_task.addBoth(cullTask)

        return self.encoder_task


    def sendMessage(self, msg, stream, whenDone=None):
        """
        Sends an RTMP message to the peer. Not part of a public api, use
        C{stream.sendMessage} instead.

        @param msg: The message being sent to the peer.
        @type msg: L{message.IMessage}
        @param stream: The stream instance that is sending the message.
        @type stream: L{NetStream}
        @param whenDone: A callback fired when the message has been written to
            the RTMP stream. See L{BaseStream.sendMessage}
        """
        buf = BufferedByteStream()
        e = self.encoder

        # this will probably need to be rethought as this could block for an
        # unacceptable amount of time. For most messages however it seems to be
        # fast enough and the penalty for setting up a new thread is too high.
        msg.encode(buf)

        e.send(buf.getvalue(), msg.__data_type__,
            stream.streamId, stream.timestamp, whenDone)

        if e.active and not self.encoder_task:
            self.startEncoding()


    def setFrameSize(self, size):
        self.sendMessage(message.FrameSize(size))
        self.encoder.setFrameSize(size)


    def getStreamingChannel(self, stream):
        """
        """
        channel = self.encoder.acquireChannel()

        if channel is None:
            # todo: make this better
            raise RuntimeError('No streaming channel available')

        return codec.StreamingChannel(channel, stream.streamId, self.getWriter())


    def onFrameSize(self, size, timestamp):
        """
        Called when the peer sets its RTMP frame size.

        @param size: The new size of any RTMP frames sent from the peer.
        @param timestamp: Time this message was received.
        """
        self.decoder.setFrameSize(size)


    def onDownstreamBandwidth(self, interval, timestamp):
        """
        Called when the peer sends its RTMP bytes interval.

        @param interval: The number of bytes that must be received from the
            peer before sending an acknowledgement
        """
        self.decoder.setBytesInterval(interval)
Exemple #4
0
class BaseStreamer(object):
    """
    Provides all the base functionality for handling an RTMP input/output.

    @ivar decoder: RTMP Decoder that is fed data via L{dataReceived}
    """

    implements(message.IMessageListener)

    dispatcher = MessageDispatcher

    @property
    def decoding(self):
        """
        Whether this streamer is currently decoding RTMP message/s.

        If all the input buffer has been consumed, this will be C{False}.
        """
        return getattr(self, 'decoding_task', None) is not None

    @property
    def encoding(self):
        """
        Whether this streamer is currently encoding RTMP message/s.
        """
        return getattr(self, 'encoding_task', None) is not None

    def getWriter(self):
        """
        Returns a file like object that provides a I{write} method. This must be
        provided by subclasses.

        For example, for L{protocol.Protocol} instances this should return
        C{self.transport}.
        """
        raise NotImplementedError

    def buildStreamManager(self):
        """
        Returns an instance that provides L{interfaces.IStreamManager}. This
        must be provided by subclasses.
        """
        raise NotImplementedError

    def getDispatcher(self):
        """
        Returns an instance that will provide L{interfaces.IMessageDispatcher}
        """
        return self.dispatcher(self)

    def bytesInterval(self, bytes):
        """
        """
        self.sendMessage(message.BytesRead(bytes), self.controlStream)

    def startStreaming(self):
        """
        This must be called before any RTMP data is received.
        """
        self.streamManager = self.buildStreamManager()
        self.controlStream = self.streamManager.getControlStream()

        self._decodingBuffer = BufferedByteStream()
        self._encodingBuffer = BufferedByteStream()

        self.decoder = codec.Decoder(self.getDispatcher(),
                                     self.streamManager,
                                     stream=self._decodingBuffer)
        self.encoder = codec.Encoder(self.getWriter(),
                                     stream=self._encodingBuffer)

        self.decoder_task = None
        self.encoder_task = None

    def stopStreaming(self, reason=None):
        """
        """
        self.streamManager.closeAllStreams()

        self._decodingBuffer.truncate()
        self._encodingBuffer.truncate()

        del self._decodingBuffer
        del self._encodingBuffer

        del self.decoder_task, self.decoder
        del self.encoder_task, self.encoder

    def dataReceived(self, data):
        """
        Data has been received by the endpoint.
        """
        self.decoder.send(data)

        if not self.decoding:
            self.startDecoding()

    def startDecoding(self):
        """
        Called to start the decoding process.

        @return: A C{Deferred} which will kill the task once the decoding is
            done or on error.
        """
        def cullTask(result):
            self.decoder_task = None

            return result

        self.decoder_task = task.coiterate(self.decoder)

        self.decoder_task.addBoth(cullTask)

        return self.decoder_task

    def startEncoding(self):
        """
        Called to start asynchronously iterate the encoder.

        @return: A C{Deferred} which will kill the task once the encoder is
            done or on error will kill the connection.
        @todo: See _startDecoding todo. The same applies here.
        """
        def cullTask(result):
            self.encoder_task = None

            return result

        self.encoder_task = task.coiterate(self.encoder)

        self.encoder_task.addBoth(cullTask)

        return self.encoder_task

    def sendMessage(self, msg, stream, whenDone=None):
        """
        Sends an RTMP message to the peer. Not part of a public api, use
        C{stream.sendMessage} instead.

        @param msg: The message being sent to the peer.
        @type msg: L{message.IMessage}
        @param stream: The stream instance that is sending the message.
        @type stream: L{NetStream}
        @param whenDone: A callback fired when the message has been written to
            the RTMP stream. See L{BaseStream.sendMessage}
        """
        buf = BufferedByteStream()
        e = self.encoder

        # this will probably need to be rethought as this could block for an
        # unacceptable amount of time. For most messages however it seems to be
        # fast enough and the penalty for setting up a new thread is too high.
        msg.encode(buf)

        e.send(buf.getvalue(), msg.__data_type__, stream.streamId,
               stream.timestamp, whenDone)

        if e.active and not self.encoder_task:
            self.startEncoding()

    def setFrameSize(self, size):
        self.sendMessage(message.FrameSize(size), self.controlStream)
        self.encoder.setFrameSize(size)

    def getStreamingChannel(self, stream):
        """
        """
        return codec.StreamingChannel(self.encoder, stream.streamId,
                                      self.getWriter())

    def onFrameSize(self, size, timestamp):
        """
        Called when the peer sets its RTMP frame size.

        @param size: The new size of any RTMP frames sent from the peer.
        @param timestamp: Time this message was received.
        """
        self.decoder.setFrameSize(size)

    def onAbort(self, channelId, timestamp):
        """
        Called to abort a channel currently be decoded.
        """
        self.decoder.abort(channelId)

    def onDownstreamBandwidth(self, interval, timestamp):
        """
        Called when the peer sends its RTMP bytes interval.

        @param interval: The number of bytes that must be received from the
            peer before sending an acknowledgement
        """
        self.decoder.setBytesInterval(interval)
Exemple #5
0
class Codec(object):
    """
    Generic channels and frame operations.

    @ivar stream: The underlying buffer containing the raw bytes.
    @type stream: L{BufferedByteStream}
    @ivar channels: A L{dict} of L{BaseChannel} objects that are handling data.
    @ivar frameSize: The maximum size for an individual frame. Read-only, use
        L{setFrameSize} instead.
    """


    def __init__(self):
        self.buffer = BufferedByteStream()

        self.channels = {}
        self.frameSize = FRAME_SIZE
        self.bytes = 0


    def setFrameSize(self, size):
        """
        Set the size of the next frame to be handled.
        """
        self.frameSize = size

        for channel in self.channels.values():
            channel.setFrameSize(size)


    def buildChannel(self, channelId):
        """
        Called to build a channel suitable for use with this codec.

        Must be implemented by subclasses.
        """
        raise NotImplementedError


    def getChannel(self, channelId):
        """
        Returns a channel based on channelId. If the channel doesn't exist,
        then one is created.

        @param channelId: Index for the channel to retrieve.
        @type channelId: C{int}
        @rtype: L{Channel}
        """
        channel = self.channels.get(channelId, None)

        if channel is not None:
            return channel

        if channelId > MAX_CHANNELS:
            raise IndexError('Attempted to get channelId %d which is > %d' % (
                channelId, MAX_CHANNELS))

        channel = self.buildChannel(channelId)
        self.channels[channelId] = channel

        channel.reset()

        return channel


    def clear(self):
        """
        Clears the underlying buffer.
        """
        self.buffer.consume()
        self.buffer.truncate()