Exemplo n.º 1
0
class OMXPlayerTests(unittest.TestCase):
    TEST_FILE_NAME = "./test.mp4"
    TEST_URL = "rtmp://192.168.0.1/live/mystream"

    def test_opens_file_in_omxplayer(self, popen, *args):
        self.patch_and_run_omxplayer()
        devnull = MOCK_OPEN()
        popen.assert_called_once_with(['omxplayer', './test.mp4'],
                                      preexec_fn=os.setsid,
                                      stdin=devnull,
                                      stdout=devnull)

    @patch('time.sleep')
    def test_tries_to_open_dbus_again_if_it_cant_connect(self, *args):
        # TODO: Shouldn't this be DBusConnectionError not SystemError
        with self.assertRaises(SystemError):
            dbus_connection = Mock(side_effect=DBusConnectionError)
            self.patch_and_run_omxplayer(Connection=dbus_connection)
            self.assertEqual(50, self.player.tries)

    def test_dbus_failure_kills(self, popen, sleep, isfile, killpg, *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        dbus_connection = Mock(side_effect=DBusConnectionError)
        with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)):
            with self.assertRaises(SystemError):
                self.patch_and_run_omxplayer(Connection=dbus_connection)
            killpg.assert_called_once_with(omxplayer_process.pid,
                                           signal.SIGTERM)

    def test_thread_failure_kills(self, popen, sleep, isfile, killpg, *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        with patch('threading.Thread', Mock(side_effect=RuntimeError)):
            with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)):
                with self.assertRaises(RuntimeError):
                    self.patch_and_run_omxplayer()
                killpg.assert_called_once_with(omxplayer_process.pid,
                                               signal.SIGTERM)

    @parameterized.expand([['can_quit', 'CanQuit', [], []],
                           ['can_set_fullscreen', 'CanSetFullscreen', [], []],
                           ['identity', 'Identity', [], []]])
    def test_root_interface_properties(self, popen, sleep, isfile, killpg,
                                       atexit, command_name, property_name,
                                       command_args, expected_dbus_call_args):
        self.patch_and_run_omxplayer()
        self.player._root_interface.dbus_interface = "org.mpris.MediaPlayer2"
        interface = self.player._properties_interface
        interface.reset_mock()

        self.patch_interface_and_run_command(command_name, command_args)

        expected_call = call.Get("org.mpris.MediaPlayer2", property_name,
                                 *expected_dbus_call_args)
        interface.assert_has_calls([expected_call])

    @parameterized.expand(
        [['pause', 'Pause', [], []], ['stop', 'Stop', [], []],
         ['seek', 'Seek', [100], [dbus.Int64(100 * 1e6)]],
         [
             'set_position', 'SetPosition', [1],
             [dbus.ObjectPath("/not/used"),
              dbus.Int64(1000000)]
         ], ['set_layer', 'SetLayer', [1], [dbus.Int64(1)]],
         ['list_subtitles', 'ListSubtitles', [], []], ['mute', 'Mute', [], []],
         ['unmute', 'Unmute', [], []], ['action', 'Action', ['p'], ['p']]])
    def test_player_interface_commands(self, popen, sleep, isfile, killpg,
                                       atexit, command_name,
                                       interface_command_name, command_args,
                                       expected_dbus_call_args):
        self.patch_and_run_omxplayer()
        self.player._player_interface.dbus_interface = "org.mpris.MediaPlayer2"
        interface = self.player._player_interface
        interface.reset_mock()

        self.patch_interface_and_run_command(command_name, command_args)

        expected_call = getattr(
            call, interface_command_name)(*expected_dbus_call_args)
        interface.assert_has_calls([expected_call])

    @parameterized.expand([
        ['can_play', 'CanPlay', True,
         dbus.Boolean(True)],
        ['can_seek', 'CanSeek', False,
         dbus.Boolean(False)],
        ['can_control', 'CanControl', True,
         dbus.Boolean(True)],
        [
            'playback_status', 'PlaybackStatus', "playing",
            dbus.String("playing")
        ],
        ['position', 'Position', 1.2,
         dbus.Int64(1.2 * 1000 * 1000)],
        ['duration', 'Duration', 10.1,
         dbus.Int64(10.1 * 1000 * 1000)],
        ['volume', 'Volume', 10, dbus.Int64(10)],
        ['minimum_rate', 'MinimumRate', 0.1,
         dbus.Double(0.1)],
        ['maximum_rate', 'MaximumRate', 4.0,
         dbus.Double(4.0)],
    ])
    def test_player_interface_properties(self, popen, sleep, isfile, killpg,
                                         atexit, command_name, property_name,
                                         expected_result, property_result):
        interface_address = "org.mpris.MediaPlayer2"
        self.patch_and_run_omxplayer()
        self.player._root_interface.dbus_interface = interface_address
        interface = self.player._properties_interface
        interface.reset_mock()
        mock = interface.Get
        mock.configure_mock(return_value=property_result)

        result = self.patch_interface_and_run_command(command_name, [])

        interface.assert_has_calls([(call.Get(interface_address,
                                              property_name))])
        self.assertEqual(expected_result, result)

    def test_quitting(self, popen, sleep, isfile, killpg, *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        self.patch_and_run_omxplayer()
        with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)):
            self.player.quit()
            killpg.assert_called_once_with(omxplayer_process.pid,
                                           signal.SIGTERM)

    def test_quitting_waits_for_omxplayer_to_die(self, popen, *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        self.patch_and_run_omxplayer()
        with patch('os.getpgid'):
            self.player.quit()
            omxplayer_process.wait.assert_has_calls([call()])

    def test_quitting_when_already_dead(self, popen, sleep, isfile, killpg,
                                        *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        self.patch_and_run_omxplayer()
        # Pretend the process is already dead
        killpg.configure_mock(side_effect=OSError)
        with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)):
            # This tests that quit handles the OSError
            self.player.quit()
            killpg.assert_called_once_with(omxplayer_process.pid,
                                           signal.SIGTERM)

    def test_quitting_twice(self, popen, sleep, isfile, killpg, *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        self.patch_and_run_omxplayer()
        with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)):
            # This should not raise, and call killpg once
            self.player.quit()
            self.player.quit()
            killpg.assert_called_once_with(omxplayer_process.pid,
                                           signal.SIGTERM)

    def test_check_process_still_exists_before_dbus_call(self, *args):
        self.patch_and_run_omxplayer()
        self.player._process = process = Mock(return_value=None)
        process.poll.return_value = None

        self.player.can_quit()

        process.poll.assert_called_once_with()

    def test_stop_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.stopEvent += callback

        self.player.stop()

        callback.assert_called_once_with(self.player)

    def test_play_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.playEvent += callback

        with patch.object(self.player, 'is_playing', return_value=False):
            self.player.play()

            callback.assert_called_once_with(self.player)

    def test_pause_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.pauseEvent += callback

        with patch.object(self.player, 'is_playing', return_value=True):
            self.player.pause()

            callback.assert_called_once_with(self.player)

    def test_play_event_by_play_pause(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.playEvent += callback

        with patch.object(self.player, 'is_playing', return_value=False):
            self.player.pause()

            # play
            self.player.play_pause()

            callback.assert_called_once_with(self.player)

    def test_pause_event_by_play_pause(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.pauseEvent += callback

        with patch.object(self.player, 'is_playing', return_value=True):
            self.player.play()

            # pause
            self.player.play_pause()

            callback.assert_called_once_with(self.player)

    def test_seek_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.seekEvent += callback

        self.player.seek(3.4)

        callback.assert_called_once_with(self.player, 3.4)

    def test_position_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.positionEvent += callback

        self.player.set_position(5.01)

        callback.assert_called_once_with(self.player, 5.01)

    def patch_interface_and_run_command(self, command_name, command_args):
        self.player._process.poll = Mock(return_value=None)
        result = getattr(self.player, command_name)(*command_args)
        return result

    # Must have the prefix 'patch' for the decorators to take effect
    def patch_and_run_omxplayer(self, Connection=Mock(), active=False):
        bus_address_finder = Mock()
        bus_address_finder.get_address.return_val = "example_bus_address"
        self.player = OMXPlayer(self.TEST_FILE_NAME,
                                bus_address_finder=bus_address_finder,
                                Connection=Connection)
        if active:
            self.player._process.poll = Mock(return_value=None)

    def patch_and_run_omxplayer_url(self, Connection=Mock(), active=False):
        bus_address_finder = Mock()
        bus_address_finder.get_address.return_val = "example_bus_address"
        self.player = OMXPlayer(self.TEST_URL,
                                bus_address_finder=bus_address_finder,
                                Connection=Connection)
        if active:
            self.player._process.poll = Mock(return_value=None)

    def test_load(self, popen, sleep, isfile, killpg, *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)):
            self.patch_and_run_omxplayer(active=True)
            # initial load
            self.assertEqual(self.player.get_filename(), './test.mp4')
            killpg.assert_not_called()
            popen.assert_called_once_with(['omxplayer', './test.mp4'],
                                          preexec_fn=os.setsid,
                                          stdin=MOCK_OPEN(),
                                          stdout=MOCK_OPEN())
            # load new video in same OMXPlayer instance
            self.player.load('./test2.mp4')
            # verify new video is registered in OMXPlayer
            self.assertEqual(self.player.get_filename(), './test2.mp4')
            # verify omxplayer process for previous video was killed
            killpg.assert_called_once_with(omxplayer_process.pid,
                                           signal.SIGTERM)
            # verify a new process was started for the second time
            self.assertEqual(popen.call_count, 2)

    def test_init_without_pause(self, *args):
        with patch.object(OMXPlayer, 'pause',
                          return_value=None) as pause_method:
            self.patch_and_run_omxplayer()
            self.assertEqual(pause_method.call_count, 0)

    def test_init_pause(self, *args):
        with patch.object(OMXPlayer, 'pause',
                          return_value=None) as pause_method:
            # self.patch_and_run_omxplayer(pause=False)
            bus_address_finder = Mock()
            bus_address_finder.get_address.return_val = "example_bus_address"
            self.player = OMXPlayer(self.TEST_FILE_NAME,
                                    bus_address_finder=bus_address_finder,
                                    Connection=Mock(),
                                    pause=True)

            self.assertEqual(pause_method.call_count, 1)

    def test_load_and_pause(self, *args):
        with patch.object(OMXPlayer, 'pause',
                          return_value=None) as pause_method:
            self.patch_and_run_omxplayer()
            self.player.load('./test2.mp4', pause=True)
            self.assertEqual(pause_method.call_count, 1)

    def test_load_without_pause(self, *args):
        with patch.object(OMXPlayer, 'pause',
                          return_value=None) as pause_method:
            self.patch_and_run_omxplayer()
            self.player.load('./test2.mp4')
            self.assertEqual(pause_method.call_count, 0)

    def test_register_quit_handler_atexit(self, popen, sleep, isfile, killpg,
                                          atexit):
        self.patch_and_run_omxplayer()
        atexit.assert_called_once_with(self.player.quit)
class OMXPlayerTests(unittest.TestCase):
    TEST_FILE_NAME = "./test.mp4"
    TEST_URL = "rtmp://192.168.0.1/live/mystream"

    def test_opens_file_in_omxplayer(self, popen, *args):
        self.patch_and_run_omxplayer()
        devnull = MOCK_OPEN()
        popen.assert_called_once_with(
            ['omxplayer', './test.mp4'],
            preexec_fn=os.setsid,
            stdin=devnull,
            stdout=devnull)

    @patch('time.sleep')
    def test_tries_to_open_dbus_again_if_it_cant_connect(self, *args):
        # TODO: Shouldn't this be DBusConnectionError not SystemError
        with self.assertRaises(SystemError):
            dbus_connection = Mock(side_effect=DBusConnectionError)
            self.patch_and_run_omxplayer(Connection=dbus_connection)
            self.assertEqual(50, self.player.tries)

    @parameterized.expand([
        ['can_quit', 'CanQuit', [], []],
        ['can_set_fullscreen', 'CanSetFullscreen', [], []],
        ['identity', 'Identity', [], []]
    ])
    def test_root_interface_properties(self, popen, sleep, isfile, killpg, atexit, command_name,
                                       property_name, command_args, expected_dbus_call_args):
        self.patch_and_run_omxplayer()
        self.player._root_interface.dbus_interface = "org.mpris.MediaPlayer2"
        interface = self.player._properties_interface
        interface.reset_mock()

        self.patch_interface_and_run_command(command_name, command_args)

        expected_call = call.Get("org.mpris.MediaPlayer2", property_name, *expected_dbus_call_args)
        interface.assert_has_calls([expected_call])

    @parameterized.expand([
        ['pause', 'Pause', [], []],
        ['stop', 'Stop', [], []],
        ['seek', 'Seek', [100], [dbus.Int64(100 * 1e6)]],
        ['set_position', 'SetPosition', [1], [dbus.ObjectPath("/not/used"), dbus.Int64(1000000)]],
        ['list_subtitles', 'ListSubtitles', [], []],
        ['mute', 'Mute', [], []],
        ['unmute', 'Unmute', [], []],
        ['action', 'Action', ['p'], ['p']]
    ])
    def test_player_interface_commands(self, popen, sleep, isfile, killpg, atexit, command_name,
                                       interface_command_name, command_args, expected_dbus_call_args):
        self.patch_and_run_omxplayer()
        self.player._player_interface.dbus_interface = "org.mpris.MediaPlayer2"
        interface = self.player._player_interface
        interface.reset_mock()

        self.patch_interface_and_run_command(command_name, command_args)

        expected_call = getattr(call, interface_command_name)(*expected_dbus_call_args)
        interface.assert_has_calls([expected_call])

    @parameterized.expand([
        ['can_play', 'CanPlay', True, dbus.Boolean(True)],
        ['can_seek', 'CanSeek', False, dbus.Boolean(False)],
        ['can_control', 'CanControl', True, dbus.Boolean(True)],
        ['playback_status', 'PlaybackStatus', "playing", dbus.String("playing")],
        ['position', 'Position', 1.2, dbus.Int64(1.2 * 1000 * 1000)],
        ['duration', 'Duration', 10.1, dbus.Int64(10.1 * 1000 * 1000)],
        ['volume', 'Volume', 10, dbus.Int64(10)],
        ['minimum_rate', 'MinimumRate', 0.1, dbus.Double(0.1)],
        ['maximum_rate', 'MaximumRate', 4.0, dbus.Double(4.0)],
    ])
    def test_player_interface_properties(self, popen, sleep, isfile, killpg, atexit,
                        command_name, property_name, expected_result, property_result):
        interface_address = "org.mpris.MediaPlayer2"
        self.patch_and_run_omxplayer()
        self.player._root_interface.dbus_interface = interface_address
        interface = self.player._properties_interface
        interface.reset_mock()
        mock = interface.Get
        mock.configure_mock(return_value=property_result)

        result = self.patch_interface_and_run_command(command_name, [])

        interface.assert_has_calls([(call.Get(interface_address, property_name))])
        self.assertEqual(expected_result, result)

    def test_quitting(self, popen, sleep, isfile, killpg, *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        self.patch_and_run_omxplayer()
        with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)):
            self.player.quit()
            killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM)

    def test_quitting_waits_for_omxplayer_to_die(self, popen, *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        self.patch_and_run_omxplayer()
        with patch('os.getpgid'):
            self.player.quit()
            omxplayer_process.wait.assert_has_calls([call()])

    def test_check_process_still_exists_before_dbus_call(self, *args):
        self.patch_and_run_omxplayer()
        self.player._process = process = Mock(return_value=None)
        process.poll.return_value = None

        self.player.can_quit()

        process.poll.assert_called_once_with()

    def test_stop_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.stopEvent += callback

        self.player.stop()

        callback.assert_called_once_with(self.player)

    def test_play_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.playEvent += callback

        with patch.object(self.player, 'is_playing', return_value=False):
            self.player.play()

            callback.assert_called_once_with(self.player)

    def test_pause_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.pauseEvent += callback

        with patch.object(self.player, 'is_playing', return_value=True):
            self.player.pause()

            callback.assert_called_once_with(self.player)

    def test_play_event_by_play_pause(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.playEvent += callback

        with patch.object(self.player, 'is_playing', return_value=False):
            self.player.pause()

            # play
            self.player.play_pause()

            callback.assert_called_once_with(self.player)

    def test_pause_event_by_play_pause(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.pauseEvent += callback

        with patch.object(self.player, 'is_playing', return_value=True):
            self.player.play()

            # pause
            self.player.play_pause()

            callback.assert_called_once_with(self.player)

    def test_seek_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.seekEvent += callback

        self.player.seek(3.4)

        callback.assert_called_once_with(self.player, 3.4)

    def test_position_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.positionEvent += callback

        self.player.set_position(5.01)

        callback.assert_called_once_with(self.player, 5.01)

    def patch_interface_and_run_command(self, command_name, command_args):
        self.player._process.poll = Mock(return_value=None)
        result = getattr(self.player, command_name)(*command_args)
        return result

    # Must have the prefix 'patch' for the decorators to take effect
    def patch_and_run_omxplayer(self, Connection=Mock(), active=False):
        bus_address_finder = Mock()
        bus_address_finder.get_address.return_val = "example_bus_address"
        self.player = OMXPlayer(self.TEST_FILE_NAME,
                                bus_address_finder=bus_address_finder,
                                Connection=Connection)
        if active:
            self.player._process.poll = Mock(return_value=None)

    def patch_and_run_omxplayer_url(self, Connection=Mock(), active=False):
        bus_address_finder = Mock()
        bus_address_finder.get_address.return_val = "example_bus_address"
        self.player = OMXPlayer(self.TEST_URL,
                                bus_address_finder=bus_address_finder,
                                Connection=Connection)
        if active:
            self.player._process.poll = Mock(return_value=None)

    def test_load(self, popen, sleep, isfile, killpg, *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)):
            self.patch_and_run_omxplayer(active=True)
            # initial load
            self.assertEqual(self.player.get_filename(), './test.mp4')
            killpg.assert_not_called()
            popen.assert_called_once_with(['omxplayer', './test.mp4'],
                                        preexec_fn=os.setsid,
                                        stdin=MOCK_OPEN(),
                                        stdout=MOCK_OPEN())
            # load new video in same OMXPlayer instance
            self.player.load('./test2.mp4')
            # verify new video is registered in OMXPlayer
            self.assertEqual(self.player.get_filename(), './test2.mp4')
            # verify omxplayer process for previous video was killed
            killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM)
            # verify a new process was started for the second time
            self.assertEqual(popen.call_count, 2)

    def test_init_without_pause(self, *args):
        with patch.object(OMXPlayer, 'pause', return_value=None) as pause_method:
            self.patch_and_run_omxplayer()
            self.assertEqual(pause_method.call_count, 0)

    def test_init_pause(self, *args):
        with patch.object(OMXPlayer, 'pause', return_value=None) as pause_method:
            # self.patch_and_run_omxplayer(pause=False)
            bus_address_finder = Mock()
            bus_address_finder.get_address.return_val = "example_bus_address"
            self.player = OMXPlayer(self.TEST_FILE_NAME,
                                bus_address_finder=bus_address_finder,
                                Connection=Mock(),
                                pause=True)

            self.assertEqual(pause_method.call_count, 1)

    def test_load_and_pause(self, *args):
        with patch.object(OMXPlayer, 'pause', return_value=None) as pause_method:
            self.patch_and_run_omxplayer()
            self.player.load('./test2.mp4', pause=True)
            self.assertEqual(pause_method.call_count, 1)

    def test_load_without_pause(self, *args):
        with patch.object(OMXPlayer, 'pause', return_value=None) as pause_method:
            self.patch_and_run_omxplayer()
            self.player.load('./test2.mp4')
            self.assertEqual(pause_method.call_count, 0)

    def test_register_quit_handler_atexit(self, popen, sleep, isfile, killpg, atexit):
        self.patch_and_run_omxplayer()
        atexit.assert_called_once_with(self.player.quit)
Exemplo n.º 3
0
class OMXPlayerTests(unittest.TestCase):
    TEST_FILE_NAME = "./test.mp4"
    TEST_URL = "rtmp://192.168.0.1/live/mystream"

    def test_opens_file_in_omxplayer(self, popen, *args):
        self.patch_and_run_omxplayer()
        devnull = MOCK_OPEN()
        popen.assert_called_once_with(
            ['omxplayer', './test.mp4'],
            preexec_fn=os.setsid,
            stdin=devnull,
            stdout=devnull)

    @patch('time.sleep')
    def test_tries_to_open_dbus_again_if_it_cant_connect(self, *args):
        # TODO: Shouldn't this be DBusConnectionError not SystemError
        with self.assertRaises(SystemError):
            dbus_connection = Mock(side_effect=DBusConnectionError)
            self.patch_and_run_omxplayer(Connection=dbus_connection)
            self.assertEqual(50, self.player.tries)

    @parameterized.expand([
        ['can_quit', 'CanQuit', [], []],
        ['can_set_fullscreen', 'CanSetFullscreen', [], []],
        ['identity', 'Identity', [], []]
    ])
    def test_root_interface_commands(self, popen, sleep, isfile, killpg, command_name,
                                     interface_command_name, *args):
        self.patch_and_run_omxplayer()
        self.patch_interface_and_run_command('_get_root_interface',
                                             command_name,
                                             interface_command_name, *args)

    @parameterized.expand([
        ['pause', 'Pause', [], []],
        ['stop', 'Stop', [], []],
        ['seek', 'Seek', [100], [100]],
        ['set_position', 'SetPosition', [1], [dbus.ObjectPath("/not/used"),
                                              dbus.Int64(1000000)]],
        ['list_subtitles', 'ListSubtitles', [], []],
        ['action', 'Action', ['p'], ['p']]
    ])
    def test_player_interface_commands(self, popen, sleep, isfile, killpg, command_name,
                                       interface_command_name, *args):
        self.patch_and_run_omxplayer()
        self.patch_interface_and_run_command('_get_player_interface',
                                             command_name,
                                             interface_command_name, *args)

    @parameterized.expand([
        ['can_play', 'CanPlay', [], []],
        ['can_seek', 'CanSeek', [], []],
        ['can_control', 'CanControl', [], []],
        ['playback_status', 'PlaybackStatus', [], []],
        ['volume', 'Volume', [], []],
        ['mute', 'Mute', [], []],
        ['unmute', 'Unmute', [], []],
        ['position', 'Position', [], []],
        ['duration', 'Duration', [], []],
        ['minimum_rate', 'MinimumRate', [], []],
        ['maximum_rate', 'MaximumRate', [], []],
    ])
    def test_properties_interface_commands(self, popen, sleep, isfile, killpg, command_name,
                                           interface_command_name, *args):
        self.patch_and_run_omxplayer()
        self.patch_interface_and_run_command('_get_properties_interface',
                                             command_name,
                                             interface_command_name, *args)

    def test_quitting(self, popen, sleep, isfile, killpg, *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        self.patch_and_run_omxplayer()
        with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)):
            self.player.quit()
            killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM)

    def test_quitting_waits_for_omxplayer_to_die(self, popen, sleep, isfile, killpg, *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        self.patch_and_run_omxplayer()
        with patch('os.getpgid'):
            self.player.quit()
            omxplayer_process.wait.assert_has_calls([call()])

    def test_check_process_still_exists_before_dbus_call(self, *args):
        self.patch_and_run_omxplayer()
        self.player._process = process = Mock(return_value=None)
        process.poll.return_value = None

        self.player.can_quit()

        process.poll.assert_called_once_with()

    def test_checks_media_file_exists_before_launching_player(self, *args):
        with patch('os.path') as ospath:
            self.patch_and_run_omxplayer()
            ospath.isfile.assert_called_once_with(self.TEST_FILE_NAME)

    def test_player_doesnt_check_source_path_exists_for_a_url(self, *args):
        with patch('os.path') as ospath:
            self.patch_and_run_omxplayer_url()
            ospath.isfile.assert_not_called()

    def test_stop_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.stopEvent += callback

        self.player.stop()

        callback.assert_called_once_with(self.player)

    def test_play_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.playEvent += callback

        with patch.object(self.player, 'is_playing', return_value=False):
            self.player.play()

            callback.assert_called_once_with(self.player)

    def test_pause_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.pauseEvent += callback

        with patch.object(self.player, 'is_playing', return_value=True):
            self.player.pause()

            callback.assert_called_once_with(self.player)

    def test_play_event_by_play_pause(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.playEvent += callback

        with patch.object(self.player, 'is_playing', return_value=False):
            self.player.pause()

            # play
            self.player.play_pause()

            callback.assert_called_once_with(self.player)

    def test_pause_event_by_play_pause(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.pauseEvent += callback

        with patch.object(self.player, 'is_playing', return_value=True):
            self.player.play()

            # pause
            self.player.play_pause()

            callback.assert_called_once_with(self.player)

    def test_seek_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.seekEvent += callback

        self.player.seek(3.4)

        callback.assert_called_once_with(self.player, 3.4)

    def test_position_event(self, *args):
        self.patch_and_run_omxplayer(active=True)
        callback = Mock()
        self.player.positionEvent += callback

        self.player.set_position(5.01)

        callback.assert_called_once_with(self.player, 5.01)

    def patch_interface_and_run_command(self, interface_name,
                                        command_name, interface_command_name,
                                        command_args,
                                        expected_args):
        self.player._process.poll = Mock(return_value=None)
        with patch.object(self.player, interface_name) as interface:
            self.run_command(command_name, *command_args)
            # generates a call of the form `call().CanQuit`
            expected_call = getattr(call(), interface_command_name)(*expected_args)
            interface.assert_has_calls([expected_call])

    def run_command(self, command_name, *args):
        command = getattr(self.player, command_name)
        command(*args)

    # Must have the prefix 'patch' for the decorators to take effect
    def patch_and_run_omxplayer(self, Connection=Mock(), active=False):
        bus_address_finder = Mock()
        bus_address_finder.get_address.return_val = "example_bus_address"
        self.player = OMXPlayer(self.TEST_FILE_NAME,
                                bus_address_finder=bus_address_finder,
                                Connection=Connection)
        if active:
            self.player._process.poll = Mock(return_value=None)

    def patch_and_run_omxplayer_url(self, Connection=Mock(), active=False):
        bus_address_finder = Mock()
        bus_address_finder.get_address.return_val = "example_bus_address"
        self.player = OMXPlayer(self.TEST_URL,
                                bus_address_finder=bus_address_finder,
                                Connection=Connection)
        if active:
            self.player._process.poll = Mock(return_value=None)

    def test_load(self, popen, sleep, isfile, killpg, *args):
        omxplayer_process = Mock()
        popen.return_value = omxplayer_process
        with patch('os.getpgid', Mock(return_value=omxplayer_process.pid)):
            self.patch_and_run_omxplayer(active=True)
            # initial load
            self.assertEqual(self.player.get_filename(), './test.mp4')
            killpg.assert_not_called()
            popen.assert_called_once_with(['omxplayer', './test.mp4'],
                                        preexec_fn=os.setsid,
                                        stdin=MOCK_OPEN(),
                                        stdout=MOCK_OPEN())
            # load new video in same OMXPlayer instance
            self.player.load('./test2.mp4')
            # verify new video is registered in OMXPlayer
            self.assertEqual(self.player.get_filename(), './test2.mp4')
            # verify omxplayer process for previous video was killed
            killpg.assert_called_once_with(omxplayer_process.pid, signal.SIGTERM)
            # verify a new process was started for the second time
            self.assertEqual(popen.call_count, 2)


    def test_init_without_pause(self, popen, sleep, isfile, killpg, *args):
        with patch.object(OMXPlayer, 'pause', return_value=None) as mock_method:
            self.patch_and_run_omxplayer()
            self.assertEqual(mock_method.call_count, 0)

    def test_init_pause(self, popen, sleep, isfile, killpg, *args):
        with patch.object(OMXPlayer, 'pause', return_value=None) as mock_method:
            # self.patch_and_run_omxplayer(pause=False)
            bus_address_finder = Mock()
            bus_address_finder.get_address.return_val = "example_bus_address"
            self.player = OMXPlayer(self.TEST_FILE_NAME,
                                bus_address_finder=bus_address_finder,
                                Connection=Mock(),
                                pause=True)

            self.assertEqual(mock_method.call_count, 1)

    def test_load_and_pause(self, popen, sleep, isfile, killpg, *args):
        with patch.object(OMXPlayer, 'pause', return_value=None) as mock_method:
            self.patch_and_run_omxplayer()
            self.player.load('./test2.mp4', pause=True)
            self.assertEqual(mock_method.call_count, 1)

    def test_load_without_pause(self, popen, sleep, isfile, killpg, *args):
        with patch.object(OMXPlayer, 'pause', return_value=None) as mock_method:
            self.patch_and_run_omxplayer()
            self.player.load('./test2.mp4')
            self.assertEqual(mock_method.call_count, 0)
Exemplo n.º 4
0
class Main:

    # Gobal Variable to store RFID reader strings and bools
    dataString = ""
    addRfidTag = False

    #Set debug logging parameters level = logging.DEBUG/ERROR/WARNING
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s - %(levelname)s - %(message)s')

    #Define serialport and parameters - aotumate later or add to setings
    try:
        ultrasoundProbe = serial.Serial(port='/dev/ttyUSB0',
                                        baudrate=115200,
                                        parity=serial.PARITY_NONE,
                                        stopbits=serial.STOPBITS_ONE,
                                        bytesize=serial.EIGHTBITS)
    except Exception as e:
        logging.debug(e)
    #Add send command to device
    # To do

    # After the combo boxes have been initialized we set them to have the same selected value
    # as during the last run
    def load_settings(self, filename):
        try:
            pickle_file = open(filename, 'rb')
            list_import = pickle.load(pickle_file)
            self.list_store1.clear()
            for i in range(len(list_import)):
                logging.debug("item " + str(list_import[i]))
                self.list_store1.append(list_import[i])
            pickle_file.close()
        except Exception as e:
            logging.debug(e)

    # Pickle the settings data for use in the next run
    def save_settings(self, filename):
        pickle_file = open(filename, 'wb')
        list_iter = self.list_store1.get_iter_root()
        list_dump = []
        while (list_iter):
            tup = self.list_store1.get(list_iter, 0, 1, 2)
            list_dump.append(list(tup))
            list_iter = self.list_store1.iter_next(list_iter)
        pickle.dump(list_dump, pickle_file)
        pickle_file.close()

    def gtk_main_quit(self, window):
        self.save_settings(sys.path[0] + "/settings.p")
        gtk.main_quit()

    def cb_quit(self, window, event):
        self.save_settings(sys.path[0] + "/settings.p")
        gtk.main_quit()

    def cb_about_press(self, window):
        response = self.about_dialog.run()
        self.about_dialog.hide()
        return response != 1

    def cb_settings_press(self, window):
        self.set_add_rfid_tag_active(True)
        response = self.settings_dialog.run()
        self.settings_dialog.hide()
        if response == gtk.RESPONSE_DELETE_EVENT:
            self.set_add_rfid_tag_active(False)
            logging.debug("close event on settings press")
        return response != 1

    def cb_add_scan_press(self, window):
        response = self.add_scan_dialog.run()
        self.add_scan_dialog.hide()
        return response != 1

    def settings_cancel_clicked(self, window):
        self.set_add_rfid_tag_active(False)
        logging.debug("Set tag false on settings exit")

    def cb_add_scan_apply_clicked(self, window):
        new_name = self.name_entry.get_text()
        new_rfid = self.rfid_entry.get_text()
        new_filename = self.filechooser.get_filename()
        self.list_store1.append([new_name, new_rfid, new_filename])
        return True

    # Callback to run when load settings button is pressed
    # Will open a window, prompt for files and update the filename variable
    def cb_load_settings_press(self, window):
        response = self.load_settings_filechooserdialog.run()
        self.load_settings_filechooserdialog.hide()
        if response == 1:
            self.load_settings(
                self.load_settings_filechooserdialog.get_filename())
        return response != 1

    # Callback to run when save settings button is pressed
    # Will open a window, prompt for files and update the filename variable
    def cb_save_settings_press(self, window):
        response = self.save_settings_filechooserdialog.run()
        self.save_settings_filechooserdialog.hide()
        if response == 1:
            self.save_settings(
                self.save_settings_filechooserdialog.get_filename())
        return response != 1

    # Opting to add a whole directory full of videos at once.
    def cb_quick_add_press(self, window):
        response = self.quick_add_dialog.run()
        self.quick_add_dialog.hide()
        return response != 1

    def cb_quick_add_ok_press(self, window):
        # Get a list of all files in the directory
        quick_add_dir = self.filechooser_quick.get_filename()
        quick_add_files = os.listdir(quick_add_dir)
        # For each of the files in the directory we will try to add a scan
        for filename in quick_add_files:
            new_filename = quick_add_dir + '/' + filename
            new_name = filename
            self.quick_add_cur_filename.set_text(filename)
            # Need to grab the focus back into the text ectry box so every scan will end by prompting fo rthe next scan
            self.rfid_quick_entry.grab_focus()
            response = self.quick_add_item.run()
            # If OK was clicked (or the scan triggered the default action)
            if response == 1:
                new_rfid = self.rfid_quick_entry.get_text()
                self.list_store1.append([new_name, new_rfid, new_filename])
            # The button was clicked, the default action is then to skip this file and read the next one
            elif response == 2:
                break
            # Blank the text entry box and get ready for new text
            self.rfid_quick_entry.set_text('')
        # The scan is done so hide the directory
        self.quick_add_item.hide()
        return True

    def cb_remove_scan_press(self, button):
        # Obtain selection
        sel = self.tree.get_selection()

        # If nothing is selected, return.
        if sel.count_selected_rows == 0:
            return

        # Get selected path
        (model, rows) = sel.get_selected_rows()
        for row in reversed(rows):
            iter1 = model.get_iter(row)
            model.remove(iter1)
        return

    #Messenger dialog box
    def message_dialog_show(self, message):
        self.message_dialog.set_property("text", message)
        response = self.message_dialog.run()
        self.message_dialog.hide()

    def on_key_press_event(self, widget, event):
        try:
            keyname = gtk.gdk.keyval_name(event.keyval)
            # Grab the letter q to stop the current movie
            if keyname == 'q' or keyname == 'Q':
                if (self.check_active_player()):
                    self.player.quit()
            #Pause on spacebar
            if keyname == 'space':
                self.player.play_pause()
            #Strings from the reader end with a new line... so we take in all characters and process the last 10 on a newline
            if keyname == 'Return':
                rfid_string_scanned = self.dataString[-10::]
                self.dataString = ''
        except Exception as e:
            print(e)

    # Play video
    def play_video(self, filename):
        if self.check_active_player():
            self.player.quit()
        print "Playing " + filename
        VIDEO_PATH = Path("" + filename + "")
        self.player = OMXPlayer(VIDEO_PATH, args=['-b'])

    # Catch exception if process is not running when checking activity
    def check_active_player(self):
        try:
            playerStatus = self.player.playback_status()
            if playerStatus == 'Playing' or playerStatus == 'Paused':
                return True
        except:
            return False
            print "Exception thrown on inactive player"

    # Callback for radio button
    def toggle_fs(self, widget, data=None):
        logging.debug("Fullscreen %s" % (("OFF", "ON")[widget.get_active()]))
        if widget.get_active():
            self.mainWindow.fullscreen()
        else:
            self.mainWindow.unfullscreen()

    def listen_serial(self):
        try:
            if (self.ultrasoundProbe.inWaiting() > 0):
                s = ''
                s += self.ultrasoundProbe.read(16)
                self.ultrasoundProbe.flushInput()
                self.dataString = s
                if (self.addRfidTag):
                    self.handle_rfid_tag_text()
                    return True
                else:
                    self.handle_video_playing()
                    logging.debug(self.dataString)
                    return True
            else:
                if self.check_active_player():
                    self.player.quit()
                logging.debug("No Tag in Range")
                return True
        except Exception as e:
            logging.debug(e)
            self.message_dialog_show(e)

    # Serial rfid tag to gui
    def handle_rfid_tag_text(self):
        rfid_string_scanned = self.dataString.strip()
        logging.debug(rfid_string_scanned)
        #Setting both add quick and add normal RFID fields to current read tag
        self.rfid_entry.set_text(rfid_string_scanned)
        self.rfid_quick_entry.set_text(rfid_string_scanned)
        self.dataString = ''

    # Continuously read rfid tags
    def handle_video_playing(self):
        logging.debug("read rfid for video playing")
        rfid_string_scanned = self.dataString.strip()
        logging.debug(rfid_string_scanned)
        self.dataString = ''

        # This code aims to check if the file is already playing so we don't continually start
        # the movie over if we are on the border of one of the tags
        # Need to check this sometimes, so always call it

        if self.check_active_player():
            current_file = str(self.player.get_filename())
        else:
            current_file = None
        #Search for the matching rfid string and play the associated file
        # Get the tree to iterate over
        list_iter = self.list_store1.get_iter_root()
        while (list_iter):
            rfid_entry = self.list_store1.get_value(list_iter, 1)
            rfid_entry = rfid_entry.strip()
            if rfid_entry == rfid_string_scanned:
                filename = self.list_store1.get_value(list_iter, 2)
                # If we are not playing a video start the one requested
                if current_file == None:
                    self.play_video(filename)
                    return filename
                # If this filename doesn't match the current playing one, fire it up
                elif filename.find(current_file) == -1:
                    self.play_video(filename)
                    return filename
                else:
                    logging.debug(
                        "Not playing %s because it is already playing" %
                        filename)
                    return True
            list_iter = self.list_store1.iter_next(list_iter)
        logging.debug("Tag not stored in settings file yet!!")
    # return True

    #Flag for scanning to play video or read tag into gui textbox

    def set_add_rfid_tag_active(self, flag=False):
        self.addRfidTag = flag
        logging.debug("add rfid status flag " + str(self.addRfidTag))

    def __init__(self):

        #Glade compomnents intialise
        self.builder = gtk.Builder()
        self.builder.add_from_file(sys.path[0] + "/EDUS2.glade")
        #Interval timer to loop listen_serial while return is true
        self.timer = gtk.timeout_add(200, self.listen_serial)

        self.window = self.builder.get_object("window1")
        self.settings_dialog = self.builder.get_object("settings_dialog")
        self.add_scan_dialog = self.builder.get_object("add_scan_dialog")
        self.quick_add_dialog = self.builder.get_object("quick_add_dialog")
        self.quick_add_item = self.builder.get_object("quick_add_item")
        self.about_dialog = self.builder.get_object("aboutdialog1")
        self.tree = self.builder.get_object("treeview2")
        self.list_store1 = self.builder.get_object("treeview")
        self.rfid_entry = self.builder.get_object("rfid_entry")
        self.rfid_quick_entry = self.builder.get_object("rfid_quick_entry")
        self.name_entry = self.builder.get_object("name_entry")
        self.quick_add_cur_filename = self.builder.get_object(
            "quick_add_cur_filename")
        self.filechooser = self.builder.get_object("filechooserbutton1")
        self.filechooser_quick = self.builder.get_object(
            "filechooserbutton_quick")
        self.load_settings_filechooserdialog = self.builder.get_object(
            "load_settings_filechooserdialog")
        self.save_settings_filechooserdialog = self.builder.get_object(
            "save_settings_filechooserdialog")
        self.message_dialog = self.builder.get_object("message_dialog")

        self.load_settings(sys.path[0] + "/settings.p")
        self.builder.connect_signals(self)

        # Set up treeView to allow multiple item selection for better delete
        self.tree.get_selection().set_mode(gtk.SELECTION_MULTIPLE)

        self.mainWindow = self.builder.get_object("window1")

        self.mainWindow.connect("key-press-event", self.on_key_press_event)
        self.window.show_all()
        self.mainWindow.fullscreen()