def process_packets(self, transaction_id=None, invoked_method=None,
                        timeout=None):
        """Wait for packets and process them as needed.

        :param transaction_id: int, Wait until the result of this
                               transaction ID is recieved.
        :param invoked_method: int, Wait until this method is invoked
                               by the server.
        :param timeout: int, The time to wait for a result from the server.
                             Note: This is the timeout used by this method only,
                             the connection timeout is still used when reading
                             packets.

        Raises :exc:`RTMPError` on error.
        Raises :exc:`RTMPTimeoutError` on timeout.

        Usage::

          >>> @conn.invoke_handler
          ... def add(x, y):
          ...   return x + y

          >>> @conn.process_packets()

        """

        start = time()

        while self.connected and transaction_id not in self._invoke_results:
            if timeout and (time() - start) >= timeout:
                raise RTMPTimeoutError("Timeout")

            packet = self.read_packet()

            if packet.type == PACKET_TYPE_INVOKE:
                try:
                    decoded = decode_amf(packet.body)
                except AMFError:
                    continue

                try:
                    method, transaction_id_, obj = decoded[:3]
                    args = decoded[3:]
                except ValueError:
                    continue

                if method == "_result":
                    if len(args) > 0:
                        result = args[0]
                    else:
                        result = None

                    self._invoke_results[transaction_id_] = result
                else:
                    handler = self._invoke_handlers.get(method)
                    if handler:
                        res = handler(*args)
                        if res is not None:
                            self.call("_result", res,
                                      transaction_id=transaction_id_)

                    if method == invoked_method:
                        self._invoke_args[invoked_method] = args
                        break

                if transaction_id_ == 1.0:
                    self._connect_result = packet
                else:
                    self.handle_packet(packet)
            else:
                self.handle_packet(packet)

        if transaction_id:
            result = self._invoke_results.pop(transaction_id, None)

            return result

        if invoked_method:
            args = self._invoke_args.pop(invoked_method, None)

            return args
Wait for packets and process them as needed.

        :param transaction_id: int, Wait until the result of this
                               transaction ID is recieved.
        :param invoked_method: int, Wait until this method is invoked
                               by the server.
        :param timeout: int, The time to wait for a result from the server.
                             Note: This is the timeout used by this method only,
                             the connection timeout is still used when reading
                             packets.

        Raises :exc:`RTMPError` on error.
        Raises :exc:`RTMPTimeoutError` on timeout.

        Usage::

          >>> @conn.invoke_handler
          ... def add(x, y):
          ...   return x + y

          >>> @conn.process_packets()