Example #1
0
 def __init__(self, mixer):
     self._lock = RLock()
     self.ports = set()
     self.mixer = mixer
     self.multiplexer = MixerPort(mixer)
     self.demultiplexer = MixerPort(mixer)
     self.multiplexer.start()
     self.demultiplexer.start()
     notification_center = NotificationCenter()
     notification_center.add_observer(ObserverWeakrefProxy(self), name='AudioPortDidChangeSlots')
Example #2
0
 def __init__(self, mixer):
     self._lock = RLock()
     self.ports = set()
     self.mixer = mixer
     self.multiplexer = MixerPort(mixer)
     self.demultiplexer = MixerPort(mixer)
     self.multiplexer.start()
     self.demultiplexer.start()
     notification_center = NotificationCenter()
     notification_center.add_observer(ObserverWeakrefProxy(self),
                                      name='AudioPortDidChangeSlots')
Example #3
0
class AudioBridge(object):
    """
    An AudioBridge is a container for objects providing the IAudioPort interface.
    It connects all such objects in a full-mesh such that all audio producers
    are connected to all consumers.

    AudioBridge implements the IAudioPort interface which means a bridge can
    contain another bridge. This must be done such that the resulting structure
    is a tree (i.e. no loops are allowed). All leafs of the tree will be
    connected as if they were the children of a single bridge.
    """

    implements(IAudioPort, IObserver)

    def __init__(self, mixer):
        self._lock = RLock()
        self.ports = set()
        self.mixer = mixer
        self.multiplexer = MixerPort(mixer)
        self.demultiplexer = MixerPort(mixer)
        self.multiplexer.start()
        self.demultiplexer.start()
        notification_center = NotificationCenter()
        notification_center.add_observer(ObserverWeakrefProxy(self),
                                         name='AudioPortDidChangeSlots')

    def __del__(self):
        self.multiplexer.stop()
        self.demultiplexer.stop()
        if len(self.ports) >= 2:
            for port1, port2 in ((wr1(), wr2())
                                 for wr1, wr2 in combinations(self.ports, 2)):
                if port1 is None or port2 is None:
                    continue
                if port1.producer_slot is not None and port2.consumer_slot is not None:
                    self.mixer.disconnect_slots(port1.producer_slot,
                                                port2.consumer_slot)
                if port2.producer_slot is not None and port1.consumer_slot is not None:
                    self.mixer.disconnect_slots(port2.producer_slot,
                                                port1.consumer_slot)
        self.ports.clear()

    def __contains__(self, port):
        return weakref.ref(port) in self.ports

    @property
    def consumer_slot(self):
        return self.demultiplexer.slot if self.demultiplexer.is_active else None

    @property
    def producer_slot(self):
        return self.multiplexer.slot if self.multiplexer.is_active else None

    def add(self, port):
        with self._lock:
            if not IAudioPort.providedBy(port):
                raise TypeError(
                    "expected object implementing IAudioPort, got %s" %
                    port.__class__.__name__)
            if port.mixer is not self.mixer:
                raise ValueError("expected port with Mixer %r, got %r" %
                                 (self.mixer, port.mixer))
            if weakref.ref(port) in self.ports:
                return
            if port.consumer_slot is not None and self.demultiplexer.slot is not None:
                self.mixer.connect_slots(self.demultiplexer.slot,
                                         port.consumer_slot)
            if port.producer_slot is not None and self.multiplexer.slot is not None:
                self.mixer.connect_slots(port.producer_slot,
                                         self.multiplexer.slot)
            for other in (wr() for wr in self.ports):
                if other is None:
                    continue
                if other.producer_slot is not None and port.consumer_slot is not None:
                    self.mixer.connect_slots(other.producer_slot,
                                             port.consumer_slot)
                if port.producer_slot is not None and other.consumer_slot is not None:
                    self.mixer.connect_slots(port.producer_slot,
                                             other.consumer_slot)
            # This hack is required because a weakly referenced object keeps a
            # strong reference to weak references of itself and thus to any
            # callbacks registered in those weak references. To be more
            # precise, we don't want the port to have a strong reference to
            # ourselves. -Luci
            self.ports.add(
                weakref.ref(port, partial(self._remove_port,
                                          weakref.ref(self))))

    def remove(self, port):
        with self._lock:
            if weakref.ref(port) not in self.ports:
                raise ValueError("port %r is not part of this bridge" % port)
            if port.consumer_slot is not None and self.demultiplexer.slot is not None:
                self.mixer.disconnect_slots(self.demultiplexer.slot,
                                            port.consumer_slot)
            if port.producer_slot is not None and self.multiplexer.slot is not None:
                self.mixer.disconnect_slots(port.producer_slot,
                                            self.multiplexer.slot)
            for other in (wr() for wr in self.ports):
                if other is None:
                    continue
                if other.producer_slot is not None and port.consumer_slot is not None:
                    self.mixer.disconnect_slots(other.producer_slot,
                                                port.consumer_slot)
                if port.producer_slot is not None and other.consumer_slot is not None:
                    self.mixer.disconnect_slots(port.producer_slot,
                                                other.consumer_slot)
            self.ports.remove(weakref.ref(port))

    def stop(self):
        with self._lock:
            for port1 in (wr() for wr in self.ports):
                if port1 is None:
                    continue
                for port2 in (wr() for wr in self.ports):
                    if port2 is None or port2 is port1:
                        continue
                    if port1.producer_slot is not None and port2.consumer_slot is not None:
                        self.mixer.disconnect_slots(port1.producer_slot,
                                                    port2.consumer_slot)
                    if port2.producer_slot is not None and port1.consumer_slot is not None:
                        self.mixer.disconnect_slots(port2.producer_slot,
                                                    port1.consumer_slot)
            self.ports.clear()
            self.multiplexer.stop()
            self.demultiplexer.stop()

    def handle_notification(self, notification):
        with self._lock:
            if weakref.ref(notification.sender) not in self.ports:
                return
            if notification.data.consumer_slot_changed:
                if notification.data.old_consumer_slot is not None and self.demultiplexer.slot is not None:
                    self.mixer.disconnect_slots(
                        self.demultiplexer.slot,
                        notification.data.old_consumer_slot)
                if notification.data.new_consumer_slot is not None and self.demultiplexer.slot is not None:
                    self.mixer.connect_slots(
                        self.demultiplexer.slot,
                        notification.data.new_consumer_slot)
                for other in (wr() for wr in self.ports):
                    if other is None or other is notification.sender or other.producer_slot is None:
                        continue
                    if notification.data.old_consumer_slot is not None:
                        self.mixer.disconnect_slots(
                            other.producer_slot,
                            notification.data.old_consumer_slot)
                    if notification.data.new_consumer_slot is not None:
                        self.mixer.connect_slots(
                            other.producer_slot,
                            notification.data.new_consumer_slot)
            if notification.data.producer_slot_changed:
                if notification.data.old_producer_slot is not None and self.multiplexer.slot is not None:
                    self.mixer.disconnect_slots(
                        notification.data.old_producer_slot,
                        self.multiplexer.slot)
                if notification.data.new_producer_slot is not None and self.multiplexer.slot is not None:
                    self.mixer.connect_slots(
                        notification.data.new_producer_slot,
                        self.multiplexer.slot)
                for other in (wr() for wr in self.ports):
                    if other is None or other is notification.sender or other.consumer_slot is None:
                        continue
                    if notification.data.old_producer_slot is not None:
                        self.mixer.disconnect_slots(
                            notification.data.old_producer_slot,
                            other.consumer_slot)
                    if notification.data.new_producer_slot is not None:
                        self.mixer.connect_slots(
                            notification.data.new_producer_slot,
                            other.consumer_slot)

    @staticmethod
    def _remove_port(selfwr, portwr):
        self = selfwr()
        if self is not None:
            with self._lock:
                self.ports.discard(portwr)
Example #4
0
class AudioBridge(object):
    """
    An AudioBridge is a container for objects providing the IAudioPort interface.
    It connects all such objects in a full-mesh such that all audio producers
    are connected to all consumers.

    AudioBridge implements the IAudioPort interface which means a bridge can
    contain another bridge. This must be done such that the resulting structure
    is a tree (i.e. no loops are allowed). All leafs of the tree will be
    connected as if they were the children of a single bridge.
    """

    implements(IAudioPort, IObserver)

    def __init__(self, mixer):
        self._lock = RLock()
        self.ports = set()
        self.mixer = mixer
        self.multiplexer = MixerPort(mixer)
        self.demultiplexer = MixerPort(mixer)
        self.multiplexer.start()
        self.demultiplexer.start()
        notification_center = NotificationCenter()
        notification_center.add_observer(ObserverWeakrefProxy(self), name='AudioPortDidChangeSlots')

    def __del__(self):
        self.multiplexer.stop()
        self.demultiplexer.stop()
        if len(self.ports) >= 2:
            for port1, port2 in ((wr1(), wr2()) for wr1, wr2 in combinations(self.ports, 2)):
                if port1 is None or port2 is None:
                    continue
                if port1.producer_slot is not None and port2.consumer_slot is not None:
                    self.mixer.disconnect_slots(port1.producer_slot, port2.consumer_slot)
                if port2.producer_slot is not None and port1.consumer_slot is not None:
                    self.mixer.disconnect_slots(port2.producer_slot, port1.consumer_slot)
        self.ports.clear()

    def __contains__(self, port):
        return weakref.ref(port) in self.ports

    @property
    def consumer_slot(self):
        return self.demultiplexer.slot if self.demultiplexer.is_active else None

    @property
    def producer_slot(self):
        return self.multiplexer.slot if self.multiplexer.is_active else None

    def add(self, port):
        with self._lock:
            if not IAudioPort.providedBy(port):
                raise TypeError("expected object implementing IAudioPort, got %s" % port.__class__.__name__)
            if port.mixer is not self.mixer:
                raise ValueError("expected port with Mixer %r, got %r" % (self.mixer, port.mixer))
            if weakref.ref(port) in self.ports:
                return
            if port.consumer_slot is not None and self.demultiplexer.slot is not None:
                self.mixer.connect_slots(self.demultiplexer.slot, port.consumer_slot)
            if port.producer_slot is not None and self.multiplexer.slot is not None:
                self.mixer.connect_slots(port.producer_slot, self.multiplexer.slot)
            for other in (wr() for wr in self.ports):
                if other is None:
                    continue
                if other.producer_slot is not None and port.consumer_slot is not None:
                    self.mixer.connect_slots(other.producer_slot, port.consumer_slot)
                if port.producer_slot is not None and other.consumer_slot is not None:
                    self.mixer.connect_slots(port.producer_slot, other.consumer_slot)
            # This hack is required because a weakly referenced object keeps a
            # strong reference to weak references of itself and thus to any
            # callbacks registered in those weak references. To be more
            # precise, we don't want the port to have a strong reference to
            # ourselves. -Luci
            self.ports.add(weakref.ref(port, partial(self._remove_port, weakref.ref(self))))

    def remove(self, port):
        with self._lock:
            if weakref.ref(port) not in self.ports:
                raise ValueError("port %r is not part of this bridge" % port)
            if port.consumer_slot is not None and self.demultiplexer.slot is not None:
                self.mixer.disconnect_slots(self.demultiplexer.slot, port.consumer_slot)
            if port.producer_slot is not None and self.multiplexer.slot is not None:
                self.mixer.disconnect_slots(port.producer_slot, self.multiplexer.slot)
            for other in (wr() for wr in self.ports):
                if other is None:
                    continue
                if other.producer_slot is not None and port.consumer_slot is not None:
                    self.mixer.disconnect_slots(other.producer_slot, port.consumer_slot)
                if port.producer_slot is not None and other.consumer_slot is not None:
                    self.mixer.disconnect_slots(port.producer_slot, other.consumer_slot)
            self.ports.remove(weakref.ref(port))

    def stop(self):
        with self._lock:
            for port1 in (wr() for wr in self.ports):
                if port1 is None:
                    continue
                for port2 in (wr() for wr in self.ports):
                    if port2 is None or port2 is port1:
                        continue
                    if port1.producer_slot is not None and port2.consumer_slot is not None:
                        self.mixer.disconnect_slots(port1.producer_slot, port2.consumer_slot)
                    if port2.producer_slot is not None and port1.consumer_slot is not None:
                        self.mixer.disconnect_slots(port2.producer_slot, port1.consumer_slot)
            self.ports.clear()
            self.multiplexer.stop()
            self.demultiplexer.stop()

    def handle_notification(self, notification):
        with self._lock:
            if weakref.ref(notification.sender) not in self.ports:
                return
            if notification.data.consumer_slot_changed:
                if notification.data.old_consumer_slot is not None and self.demultiplexer.slot is not None:
                    self.mixer.disconnect_slots(self.demultiplexer.slot, notification.data.old_consumer_slot)
                if notification.data.new_consumer_slot is not None and self.demultiplexer.slot is not None:
                    self.mixer.connect_slots(self.demultiplexer.slot, notification.data.new_consumer_slot)
                for other in (wr() for wr in self.ports):
                    if other is None or other is notification.sender or other.producer_slot is None:
                        continue
                    if notification.data.old_consumer_slot is not None:
                        self.mixer.disconnect_slots(other.producer_slot, notification.data.old_consumer_slot)
                    if notification.data.new_consumer_slot is not None:
                        self.mixer.connect_slots(other.producer_slot, notification.data.new_consumer_slot)
            if notification.data.producer_slot_changed:
                if notification.data.old_producer_slot is not None and self.multiplexer.slot is not None:
                    self.mixer.disconnect_slots(notification.data.old_producer_slot, self.multiplexer.slot)
                if notification.data.new_producer_slot is not None and self.multiplexer.slot is not None:
                    self.mixer.connect_slots(notification.data.new_producer_slot, self.multiplexer.slot)
                for other in (wr() for wr in self.ports):
                    if other is None or other is notification.sender or other.consumer_slot is None:
                        continue
                    if notification.data.old_producer_slot is not None:
                        self.mixer.disconnect_slots(notification.data.old_producer_slot, other.consumer_slot)
                    if notification.data.new_producer_slot is not None:
                        self.mixer.connect_slots(notification.data.new_producer_slot, other.consumer_slot)

    @staticmethod
    def _remove_port(selfwr, portwr):
        self = selfwr()
        if self is not None:
            with self._lock:
                self.ports.discard(portwr)