示例#1
0
    def __init__(self):
        super().__init__()
        signal.signal(signal.SIGUSR1, self.handler)
        signal.signal(signal.SIGINT, self.termination_handler)
        self.remote_msg = dict()
        self.remotes_termination = threading.Event()
        self.remote_event = threading.Event(
        )  # Event for signaling control thread(s) events to main thread
        self.reply_event = threading.Event()
        self.control_pipe = ControlPipe(self.remote_event, self.remote_msg)
        self.bt_remote = BtRemote(self.remote_event, self.remote_msg)

        # TODO: maybe refractor into player_methods and always eval()?
        self.media_control_methods = [
            f for f in dir(MediaControl)
            if not f.startswith('_') and callable(getattr(MediaControl, f))
        ]
        self.media_info_methods = [
            f for f in dir(MediaInfo)
            if not f.startswith('_') and callable(getattr(MediaInfo, f))
        ]
        self.player = StoragePlayer()
        self.encoder = Encoder()

        if config.get_settings()["PIRATERADIO"]["output"] == "fm":
            self.output = FmOutput()
        else:
            self.output = AnalogOutput()
示例#2
0
    def __init__(self):
        signal.signal(signal.SIGUSR1, self.handler)
        signal.signal(signal.SIGINT, self.termination_handler)
        self.remote_msg = dict()
        self.check_remotes_termination = threading.Event()
        self.remote_event = threading.Event(
        )  # Event for signaling control thread(s) events to main thread
        self.control_pipe = ControlPipe(self.remote_event, self.remote_msg)
        # Bluetooth setup (only if a2dp is supported)
        # if which("bluealsa") is not None:
        #     self.bt_daemon = BluetoothDaemon()

        # TODO: maybe refractor into player_methods end always eval()?
        self.media_control_methods = [
            f for f in dir(MediaControl)
            if not f.startswith('_') and callable(getattr(MediaControl, f))
        ]
        self.media_info_methods = [
            f for f in dir(MediaInfo)
            if not f.startswith('_') and callable(getattr(MediaInfo, f))
        ]
        self.player = StoragePlayer()
        self.encoder = Encoder()

        if config.get_settings()["PIRATERADIO"]["output"] == "fm":
            self.output = FmOutput()
        else:
            self.output = AnalogOutput()
示例#3
0
class Mpradio:

    control_pipe = None
    bt_remote = None
    gpio_remote = None
    remote_event = None
    remote_msg = None
    media_control_methods = None
    media_info_methods = None
    remotes_termination = None

    player = None
    encoder = None
    output = None

    def __init__(self):
        super().__init__()
        signal.signal(signal.SIGUSR1, self.handler)
        signal.signal(signal.SIGINT, self.termination_handler)
        self.remote_msg = dict()
        self.remotes_termination = threading.Event()
        self.remote_event = threading.Event(
        )  # Event for signaling control thread(s) events to main thread
        self.reply_event = threading.Event()
        self.control_pipe = ControlPipe(self.remote_event, self.remote_msg)
        self.bt_remote = BtRemote(self.remote_event, self.remote_msg)

        # TODO: maybe refractor into player_methods and always eval()?
        self.media_control_methods = [
            f for f in dir(MediaControl)
            if not f.startswith('_') and callable(getattr(MediaControl, f))
        ]
        self.media_info_methods = [
            f for f in dir(MediaInfo)
            if not f.startswith('_') and callable(getattr(MediaInfo, f))
        ]
        self.player = StoragePlayer()
        self.encoder = Encoder()

        if config.get_settings()["PIRATERADIO"]["output"] == "fm":
            self.output = FmOutput()
        else:
            self.output = AnalogOutput()

    def handler(self, signum, frame):
        print("received signal", signum)

    def termination_handler(self, signum, frame):
        print("stopping threads and clean termination...")
        self.remotes_termination.set()
        self.player.stop()
        self.encoder.stop()
        self.output.stop()
        quit(0)

    def run(self):
        self.player.run()
        self.encoder.run()
        self.output.run()
        self.bt_remote.run()
        self.control_pipe.listen()
        if platform.machine() != "x86_64":
            from gpio_remote import GpioRemote
            self.gpio_remote = GpioRemote(self.remote_event, self.remote_msg)
            self.gpio_remote.run()

        threading.Thread(target=self.check_remotes).start()

        # wait for the player to be ready and pre-buffer
        self.player.ready.wait()
        data = self.player.output_stream.read(self.player.CHUNK)
        print("player is ready")

        # play stream
        while True:
            try:
                if data is not None:
                    self.encoder.ready.wait()
                    self.encoder.input_stream.write(data)
                else:
                    # print("waiting for player data")
                    raise AttributeError
                self.encoder.ready.wait()
                encoded = self.encoder.output_stream.read(self.player.CHUNK)
                if encoded is not None:  # send the encoded data to output, if any
                    self.output.ready.wait()
                    self.output.input_stream.write(encoded)
                else:
                    # print("waiting for encoder data")
                    raise AttributeError
            except AttributeError:
                time.sleep(self.player.SLEEP_TIME
                           )  # avoid 100% CPU when player is paused
            # advance the "play head"
            self.player.ready.wait()
            data = self.player.output_stream.read(self.player.CHUNK)
            # print("advancing playhead...")

    def check_remotes(self):
        while not self.remotes_termination.is_set():
            time.sleep(0.2)
            if self.remote_event.is_set():
                self.remote_event.clear()
                try:
                    cmd = self.remote_msg["command"]
                except KeyError:
                    continue

                if cmd[0] in self.media_control_methods:
                    exec("self.player." + cmd[0] + "()")
                elif cmd[0] in self.media_info_methods:
                    result = eval("self.player." + cmd[0] + "()")
                    if self.remote_msg["source"] == "bluetooth":
                        self.bt_remote.reply(result)
                elif cmd[0] == "bluetooth":
                    if cmd[1] == "attach":
                        if self.player.__class__.__name__ == "BtPlayer":
                            continue
                        tmp = BtPlayer(cmd[2])
                        tmp.run()
                        tmp.ready.wait()
                        self.player.stop()
                        self.player = tmp
                        print("bluetooth attached")
                    elif cmd[1] == "detach":
                        if self.player.__class__.__name__ != "BtPlayer":
                            continue
                        tmp = StoragePlayer()
                        tmp.run()
                        tmp.ready.wait()
                        self.player.stop()
                        self.player = tmp
                        print("bluetooth detached")
                elif cmd[0] == "system":
                    if cmd[1] == "poweroff":
                        self.player.pause()
                        call(["sudo", "poweroff"])
                    elif cmd[1] == "reboot":
                        call(["sudo", "reboot"])
                elif cmd[0] == "play":
                    if self.player.__class__.__name__ != "StoragePlayer":
                        continue
                    what = json.loads(self.remote_msg["data"])
                    self.player.play_on_demand(what)
                elif cmd[0] == "playlist":
                    try:
                        with open(config.get_playlist_file()
                                  ) as file:  # TODO: implement in player
                            pl = str(json.load(file))
                            self.bt_remote.reply(pl)
                    except FileNotFoundError:
                        pass
                elif cmd[0] == "library":
                    try:
                        with open(config.get_library_file()) as file:
                            lib = str(json.load(file))
                            self.bt_remote.reply(lib)
                    except FileNotFoundError:
                        pass
                elif cmd[0] == "config":
                    if cmd[1] == "get":
                        self.bt_remote.reply(config.to_json())
                    elif cmd[1] == "set":
                        cfg = self.remote_msg["data"]
                        self.apply_configuration(cfg)
                    elif cmd[
                            1] == "reload":  # TODO: remove. this is for testing purposes only
                        self.reload_configuration()
                else:
                    print("unknown command received:", cmd)
                self.remote_msg.clear()  # clean for next usage

        # Remote checker termination
        self.control_pipe.stop()
        self.bt_remote.stop()
        if self.gpio_remote is not None:
            self.gpio_remote.stop()

    def apply_configuration(self, cfg):
        config.load_json(cfg)
        self.reload_configuration()

    def reload_configuration(self):
        self.player.pause(
        )  # player must be paused/silenced to avoid audio feed loop on fm transmission
        self.encoder.reload()  # encoded must be reloaded to avoid broken pipe
        self.output.check_reload()  # don't restart output if not needed
        self.player.resume()
示例#4
0
class Mpradio:

    control_pipe = None
    bt_remote = None
    gpio_remote = None
    remote_event = None
    remote_msg = None
    media_control_methods = None
    media_info_methods = None
    remotes_termination = None

    player = None
    encoder = None
    output = None

    def __init__(self):
        super().__init__()
        signal.signal(signal.SIGUSR1, self.handler)
        signal.signal(signal.SIGINT, self.termination_handler)
        self.remote_msg = dict()
        self.remotes_termination = threading.Event()
        self.remote_event = threading.Event(
        )  # Event for signaling control thread(s) events to main thread
        self.reply_event = threading.Event()
        self.control_pipe = ControlPipe(self.remote_event, self.remote_msg)
        self.bt_remote = BtRemote(self.remote_event, self.remote_msg)

        # TODO: maybe refractor into player_methods and always eval()?
        self.media_control_methods = [
            f for f in dir(MediaControl)
            if not f.startswith('_') and callable(getattr(MediaControl, f))
        ]
        self.media_info_methods = [
            f for f in dir(MediaInfo)
            if not f.startswith('_') and callable(getattr(MediaInfo, f))
        ]
        self.player = StoragePlayer()
        self.encoder = Encoder()

        if config.get_settings()["PIRATERADIO"]["output"] == "fm":
            self.output = FmOutput()
        else:
            self.output = AnalogOutput()

    def handler(self, signum, frame):
        print("received signal", signum)

    def termination_handler(self, signum, frame):
        print("stopping threads and clean termination...")
        self.remotes_termination.set()
        self.player.stop()
        self.encoder.stop()
        self.output.stop()
        quit(0)

    def run(self):
        self.encoder.run()
        self.output.run()
        self.player.set_out_stream(self.output.input_stream)
        self.player.run()
        self.bt_remote.run()
        self.control_pipe.listen()
        if platform.machine() != "x86_64":
            from gpio_remote import GpioRemote
            self.gpio_remote = GpioRemote(self.remote_event, self.remote_msg)
            self.gpio_remote.run()

        threading.Thread(target=self.check_remotes).start()
        '''
        # play stream
        while True:
            self.player.ready.wait()
            data = self.player.output_stream.read()

            if data is not None:
                self.output.ready.wait()
                self.output.input_stream.write(data)
                t = 0.005
                wait_time = ((len(data)/4)/44.1) * 0.001
                # print("just read", len(data), "bytes. sleeping for", wait_time, "-", t)
                if wait_time >= t:
                    wait_time -= t
                time.sleep(wait_time)
            # print("advancing playhead...")
        '''

    def check_remotes(self):
        while not self.remotes_termination.is_set():
            time.sleep(0.02)
            if self.remote_event.is_set():
                self.remote_event.clear()
                try:
                    cmd = self.remote_msg["command"]
                except KeyError:
                    continue

                if cmd[0] in self.media_control_methods:
                    exec("self.player." + cmd[0] + "()")
                elif cmd[0] in self.media_info_methods:
                    result = eval("self.player." + cmd[0] + "()")
                    if self.remote_msg["source"] == "bluetooth":
                        self.bt_remote.reply(result)
                elif cmd[0] == "bluetooth":
                    if cmd[1] == "attach":
                        mac = get_connected_device()
                        if self.player.__class__.__name__ == "BtPlayerLite" or mac is None:
                            continue
                        tmp = BtPlayerLite(mac)
                        self.player.stop()
                        self.player = tmp
                        self.player.set_out_stream(self.output.input_stream)
                        self.player.run()
                        print("bluetooth attached")
                    elif cmd[1] == "detach":
                        if self.player.__class__.__name__ != "BtPlayerLite":
                            continue
                        self.player.stop()
                        self.player = StoragePlayer()
                        self.player.set_out_stream(self.output.input_stream)
                        self.player.run()
                        # self.player.ready.wait()
                        print("bluetooth detached")
                elif cmd[0] == "system":
                    if cmd[1] == "poweroff":
                        self.player.pause()
                        call(["sudo", "poweroff"])
                    elif cmd[1] == "reboot":
                        self.player.pause()
                        call(["sudo", "reboot"])
                    elif cmd[1] == "wifi-switch" and cmd[2] == "status":
                        if self.remote_msg["source"] == "bluetooth":
                            result = Popen(cmd[1:],
                                           stdout=PIPE).stdout.read().decode()
                            self.bt_remote.reply(result)
                    else:
                        call(["sudo"] + cmd[1:])

                elif cmd[0] == "play":
                    if self.player.__class__.__name__ != "StoragePlayer":
                        continue
                    what = json.loads(self.remote_msg["data"])
                    self.player.play_on_demand(what)
                elif cmd[0] == "playlist":
                    try:
                        with open(config.get_playlist_file()
                                  ) as file:  # TODO: implement in player
                            pl = str(json.load(file))
                            self.bt_remote.reply(pl)
                    except FileNotFoundError:
                        pass
                elif cmd[0] == "library":
                    try:
                        with open(config.get_library_file()) as file:
                            lib = str(json.load(file))
                            self.bt_remote.reply(lib)
                    except FileNotFoundError:
                        pass
                elif cmd[0] == "config":
                    if cmd[1] == "get":
                        self.bt_remote.reply(config.to_json())
                    elif cmd[1] == "set":
                        cfg = self.remote_msg["data"]
                        self.apply_configuration(cfg)
                    elif cmd[
                            1] == "reload":  # TODO: remove. this is for testing purposes only
                        self.reload_configuration()
                else:
                    print("unknown command received:", cmd)
                self.remote_msg.clear()  # clean for next usage

        # Remote checker termination
        self.control_pipe.stop()
        self.bt_remote.stop()
        if self.gpio_remote is not None:
            self.gpio_remote.stop()

    def apply_configuration(self, cfg):
        config.load_json(cfg)
        self.reload_configuration()

    def reload_configuration(self):
        self.player.pause(
        )  # player must be paused/silenced to avoid audio feed loop on fm transmission
        self.encoder.reload()  # encoded must be reloaded to avoid broken pipe
        self.output.check_reload()  # don't restart output if not needed
        self.player.resume()
示例#5
0
class Mpradio:

    bt_daemon = None
    control_pipe = None
    gpio_remote = None
    remote_event = None
    remote_msg = None
    media_control_methods = None
    media_info_methods = None
    check_remotes_termination = None

    player = None
    encoder = None
    output = None

    def __init__(self):
        signal.signal(signal.SIGUSR1, self.handler)
        signal.signal(signal.SIGINT, self.termination_handler)
        self.remote_msg = dict()
        self.check_remotes_termination = threading.Event()
        self.remote_event = threading.Event(
        )  # Event for signaling control thread(s) events to main thread
        self.control_pipe = ControlPipe(self.remote_event, self.remote_msg)
        # Bluetooth setup (only if a2dp is supported)
        # if which("bluealsa") is not None:
        #     self.bt_daemon = BluetoothDaemon()

        # TODO: maybe refractor into player_methods end always eval()?
        self.media_control_methods = [
            f for f in dir(MediaControl)
            if not f.startswith('_') and callable(getattr(MediaControl, f))
        ]
        self.media_info_methods = [
            f for f in dir(MediaInfo)
            if not f.startswith('_') and callable(getattr(MediaInfo, f))
        ]
        self.player = StoragePlayer()
        self.encoder = Encoder()

        if config.get_settings()["PIRATERADIO"]["output"] == "fm":
            self.output = FmOutput()
        else:
            self.output = AnalogOutput()

    def handler(self, signum, frame):
        print("received signal", signum)

    def termination_handler(self, signum, frame):
        print("stopping threads and clean termination...")
        self.check_remotes_termination.set()
        self.control_pipe.stop()
        self.player.stop()
        self.encoder.stop()
        self.output.stop()
        quit(0)

    def run(self):
        # TODO: use some synchronization mechanism to ensure consistency player -> encoder -> output
        self.player.run()
        self.encoder.run()
        self.output.start()

        # TODO: start other control threads here (remotes) using the same event for all
        self.control_pipe.listen()
        if platform.machine() != "x86_64":
            from gpio_remote import GpioRemote
            self.gpio_remote = GpioRemote(self.remote_event, self.remote_msg)
            self.gpio_remote.run()

        threading.Thread(target=self.check_remotes).start()

        # wait for the player to spawn
        while self.player.stream is None:
            time.sleep(0.2)

        # pre-buffer
        data = self.player.stream.stdout.read(self.player.CHUNK)

        # play stream
        while True:
            try:
                if data is not None:
                    self.encoder.stream.stdin.write(data)
                else:  # avoid 100% CPU when player is paused
                    # print("waiting for player data")
                    raise AttributeError
                encoded = self.encoder.stream.stdout.read(
                    self.player.CHUNK)  # must be non-blocking
                if encoded is not None:  # send the encoded data to output, if any
                    self.output.stream.stdin.write(encoded)
                else:
                    # print("waiting for encoder data")
                    raise AttributeError
            except AttributeError:
                time.sleep(self.player.SLEEP_TIME)
            # advance the "play head"
            if self.player.stream is not None:
                data = self.player.stream.stdout.read(
                    self.player.CHUNK)  # must be non-blocking

    def check_remotes(self):
        while not self.check_remotes_termination.is_set():
            time.sleep(0.2)
            if self.remote_event.is_set():
                self.remote_event.clear()
                if self.remote_msg["command"][0] in self.media_control_methods:
                    print("command received:", self.remote_msg["command"][0])
                    exec("self.player." + self.remote_msg["command"][0] + "()")
                    # exec("threading.Thread(target="+"self.player." + self.remote_msg["command"][0] + ").start()")
                elif self.remote_msg["command"][0] in self.media_info_methods:
                    print(
                        eval("self.player." + self.remote_msg["command"][0] +
                             "()"))
                    # TODO: check the source (remote_msg["source"] and send the reply accordingly
                elif self.remote_msg["command"][0] == "bluetooth":
                    if self.remote_msg["command"][1] == "attach":
                        self.player.pause()
                        time.sleep(4)
                        self.player.stop()
                        self.player = BtPlayer(self.remote_msg["command"][2])
                        threading.Thread(target=self.player.run).start()
                        print("bluetooth attached")
                    elif self.remote_msg["command"][1] == "detach":
                        self.player.stop()
                        self.player = StoragePlayer()
                        threading.Thread(target=self.player.run).start()
                        print("bluetooth detached")
                elif self.remote_msg["command"][0] == "system":
                    if self.remote_msg["command"][1] == "poweroff":
                        call(["sudo", "poweroff"])
                    elif self.remote_msg["command"][1] == "reboot":
                        call(["sudo", "reboot"])
                else:
                    print("unknown command received:",
                          self.remote_msg["command"][0])
                self.remote_msg.clear()  # clean for next usage