19 September 2018

Пишем приложение для удаленного управления плеером MPV из RetroOrangePi

Development of mobile applicationsDevelopment for AndroidKotlinDIY
Многие пользователи медиацентра KODI, входящего в состав RetroOrangePi, наверняка заметили, что там используется внешний плеер MPV, который, в отличии от штатного, имеет поддержку аппаратного декодирования. Это позволяет проигрывать контент 1080P без лагов, однако есть и большая проблема — единственный способ управлять плеером это клавиатура. Более того — у плеера нет даже минимального GUI, так что какой продолжительности фильм вы смотрите, и сколько еще осталось до конца — увы, не узнать.

Я, признаюсь, очень ленивый человек, и таскать за собой еще и клавиатуру, с учетом того, что сам KODI управляется с телефона — очень не удобно. Погуглив пару минут, я с удивлением узнал, что не существует готовых решений для удаленного управления MPV с смартфона. Ну что делать — придется написать самому. Кстати, как оказалось, в центре Витебска купить недорогую беспроводную клавиатуру за 1 час обеденного перерыва — тот еще квест.

MPV поддерживает несколько языков для написания скриптов, один из них Lua. На Гитхабе я нашел проект mpv-network-commands, написанный на Lua и позволяющий управлять минимум функций MPV, при помощи команд, передаваемых посредством UDP. Убедившись, что он работает, я во время обеденного перерыва написал простейшее приложение, которое реализовывало максимально примитивный функционал — по сути, оно позволяло поставить на паузу, запустить воспроизведение с паузы и закрыть плеер.


Выглядело оно примерно так.

Чтобы иметь возможность перематывать видео, а так же видеть прогресс-бар, пришлось модифицировать исходный скрипт, добавив следующую функцию:

function send_name()
local title =mp.get_property("media-title");
local length = math.floor(mp.get_property("length"));
local pos=math.floor(mp.get_property("time-pos"));
conn_up:sendto(title.."$"..length.."$"..pos, "192.168.100.168", 756);
end

Самое смешное — это то, что код, обрабатывающий входящие данные со стороны телефона, получился куда более громоздким:

И это еще без кода таймера
 thread {
            // this thread receives incoming massages from MPV and updates views accordingly to received info

            try {
                chnl.socket().bind(InetSocketAddress(756))

                chnl.configureBlocking(false)
                var timerStarted: Boolean = false
                var timer = Timer()
                while (true) {
                    var buf = ByteBuffer.allocate(1024)
                    buf.clear()
                    var last_pos = ""
                    if (!timerStarted) {
                        timer = Timer()
                        timer.schedule(myTimerTask(textView5, textView6, textView4, seekBar3), 2000, 1000)
                        //this timer will clear views, if no info received in last 2 seconds
                        timerStarted = true
                    }
                    if (chnl.isOpen) {
                        if (chnl.receive(buf) != null) {
                            if (timerStarted) {
                                timer.cancel()
                                timerStarted = false
                            }
                            var data_length = buf.position()
                            buf.flip()
                            var str = String(buf.array(), 0, data_length, UTF_8)
                            Log.d("received data", str)
                            val arr = str.split("$")
                            if (arr.size >= 3) {
                                media_length = arr[1].toInt()
                                runOnUiThread {
                                    if (textView4.text != arr[0]) textView4.text = arr[0]
                                    if (last_pos != arr[1]) {
                                        last_pos = arr[1]
                                        textView6.text = convertSecsToFullTime(last_pos)
                                    }
                                    if (!blockview) {
                                        textView5.text = convertSecsToFullTime(arr[2])
                                    seekBar3.max = arr[1].toInt()
                                        seekBar3.progress = arr[2].toInt()
                                    }

                                }
                            }
                        }
                    }
                }
            } catch (e: Exception) {
                runOnUiThread {
                    Toast.makeText(this, e.message, Toast.LENGTH_SHORT).show()
                }
                Log.d("In MPVremote", e.message.toString())
            }
        }


В результате получилось вот это:


Исходные коды, а также apk, лежат на Гитхабе.

Сразу предупреждаю — могут быть точно есть баги.

Основной недостаток — требуется фиксированный IP для телефона в вашей локальной сети, в которой работает OrangePi. Он необходим, что бы скрипт знал, куда ему отправлять инфу о воспроизводимом файле. Самый простой способ — в настройках DHCP сервера вашего роутера указать выдавать один и тот же IP устройствам с МАК-адресом телефона.

Также нет никаких элементов безопасности — любой пользователь в вашей сети сможет поставить видео на паузу или закрыть плеер, зная IP медиацентра. Правда, узнать что воспроизводится и воспроизводится ли вообще — нет.

Кстати, использование обмена данными через UDP безо всяких подтверждений порождает побочный эффект — поскольку прием входящих данных от плеера крутится в отдельном потоке, то вы можете ставить/снимать паузу и закрывать плеер, даже если не указали серверному скрипту правильный IP вашего телефона. Главное, что бы вы знали IP вашего медиацентра.

Установка

Перейдите в Desktop RetroOrangePi. Сначала надо установить Lua и LuaSocket.

sudo apt-get install lua5.1 luasocket

Затем перейдите в директорию /home/pi/.config/mpv/ и создайте там директорию lua.

В lua скопируйте server.lua.

Откройте server.lua тем же nano и в строке

conn_up:sendto(title.."$"..length.."$"..pos, "192.168.100.168", 756);

замените IP адрес на адрес вашего телефона.

Сохраните и перезагрузите OrangePi.

Установите приложение на телефон. Собранный apk лежит на Гитхабе. Запустите его, перейдите в Settings. Задайте там IP вашего медиацентра и порт 755. Нажмите Save.

Всё, можно пользоваться.
Tags:MPVKODIRetroOrangePiorangepi
Hubs: Development of mobile applications Development for Android Kotlin DIY
+13
4.2k 32
Comments 12