Форум сайта python.su
Нужна помощь.Нужно реализовать функцию вопроизведения звукового фала по кругу.
Пример после нажатия на кнопку клавиатуры up непрерывно играет wav файл до тех пор пока кнопку up не отпустят.
#!/usr/bin/env python # -*- coding: utf-8 -*- # Based on http://www.marsohod.org/index.php/projects/plata1/205-carctrlandr import os import BaseHTTPServer from threading import Thread import urlparse import time import string try: import android droid = android.Android() except ImportError: def mediaPlay(path): print "PLAY", path import mock droid = mock.Mock() droid.mediaPlay = mediaPlay HOST_NAME = '' PORT_NUMBER = 9090 COMMAND_SEND_INTERVAL = 1.0 # seconds COMMAND_TIMEOUT = COMMAND_SEND_INTERVAL * 2 PAGE_TEMPLATE = ''' <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>DroidBot Remote Control</title> </head> <FRAMESET ROWS="67%,33%"> <FRAME SRC="frame_a.html"> <FRAME SRC="frame_b.html"> </FRAMESET> </html> ''' PAGE_TEMPLATE_A = ''' <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> </head> <body> <center> <iframe scrolling="no" width="640" height="480" src ="http://%s:8080/videofeed">No iframes?</iframe> </center> </body> </html> ''' PAGE_TEMPLATE_B = string.Template(''' <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>DroidBot Remote Control</title> <style type="text/css"> #action { background:yellow; border:0px solid #555; color:#555; width:0px; height:0px; padding:0px; } #joystick { background: black; color: white; width: 100%; height: 100%; overflow: hidden; padding: 0; margin: 0; -webkit-user-select: none; -moz-user-select: none; } .btn{ width: 7em; height: 2em; } </style> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <script src="//jeromeetienne.github.com/virtualjoystick.js/virtualjoystick.js"></script> <script> $(document).ready(function(){ function CommandSender(cmdInterval){ this.cmdInterval = cmdInterval; this.lastCmd = ""; this.lastState = ""; this.lastTime = new Date(); } CommandSender.prototype.run = function(){ var $this = this; setInterval(function(){ $this.updateState($this.lastState, $this.lastCmd); }, this.cmdInterval); } CommandSender.prototype.updateState = function(state, cmd){ if((new Date() - this.lastTime) < this.cmdInterval && cmd == this.lastCmd && state == this.lastState) return; if (state == "begin" && cmd){ this.sendCommand(state, cmd); } else if (state != this.lastState) { this.sendCommand("end", cmd); } this.lastState = state; this.lastCmd = cmd; this.lastTime = new Date(); } CommandSender.prototype.sendCommand = function(state, cmd){ $.post('command/' + state + ':' + cmd, function(resp){ console.log(resp); }); } var cmdInterval = ${COMMAND_SEND_INTERVAL}; (function buttonsHandler(){ var sender = new CommandSender(cmdInterval); $(".btn").mousedown(function(){ sender.updateState("begin", $(this).data("command")); }).mouseup(function(){ sender.updateState("end", $(this).data("command")); }).mouseleave(function(){ sender.updateState("end", ""); }); sender.run(); })(); (function keyBoardHandler(){ var sender = new CommandSender(cmdInterval); var arrow = {37: 'left', 38: 'up', 39: 'right', 40:'down'}; $(document).keydown(function (e) { var keyCode = e.keyCode || e.which; var cmd = arrow[keyCode]; if (cmd) sender.updateState("begin", cmd); }).keyup(function (e) { sender.updateState("end", ""); }); sender.run(); })(); (function joystickHandler(){ var joystick = new VirtualJoystick({ container : document.getElementById('joystick'), mouseSupport : true }); var sender = new CommandSender(cmdInterval); setInterval(function(){ var cmd = "" var state = "begin"; if(joystick.up()){ cmd = "up"; } else if (joystick.down()) { cmd = "down"; } else if (joystick.left()) { cmd = "left"; } else if (joystick.right()) { cmd = "right"; } else { state = "end"; } sender.updateState(state, cmd); }, 1/30 * 1000); })(); }); </script> </head> <body> <center> <table border=0> <tr> <td></td> <td><button class="btn" data-command="up">Up</button></td> <td></td> </tr> <tr> <td><button class="btn" data-command="left">Left</button></td> <td></td> <td><button class="btn" data-command="right">Right</button></td> </tr> <tr> <td></td> <td><button class="btn" data-command="down">Down</button></td> <td></td> </tr> </table> <div id="joystick">Joystick area. Press and drag (touch or mouse). Or use keyboard arrows</div> </center> </body> </html> ''').safe_substitute(COMMAND_SEND_INTERVAL=int(COMMAND_SEND_INTERVAL * 1000)) class CarControllerThread(Thread): path_to_audio = '/mnt/sdcard/droid_car/' command_to_audio = { 'up': 'up.wav', 'down': 'down.wav', 'left': 'left.wav', 'right': 'right.wav', } def __init__(self, timeout=1): super(CarControllerThread, self).__init__() self.timeout = timeout self.pool_timeout = timeout / 3.0 self.current_state = "" self.current_command = "" self.last_cmd_timestamp = time.time() def run(self): while True: elapsed = time.time() - self.last_cmd_timestamp if self.current_state == "begin" and elapsed > self.timeout: self.update_state("end", "") time.sleep(self.pool_timeout) def update_state(self, state, command): self.last_cmd_timestamp = time.time() if state == self.current_state and command == self.current_command: return self.current_state = state self.current_command = command if state == "end": print "PAUSE" droid.mediaPlaySetLooping(False) droid.mediaPlayPause() elif state == "begin": print "PLAY", command audio = self.command_to_audio.get(command) if audio: droid.mediaPlay(os.path.join(self.path_to_audio, audio)) droid.mediaPlaySetLooping(True) else: print "wrong command:", command class DroidHandler(BaseHTTPServer.BaseHTTPRequestHandler): def do_HEAD(self): self.send_response(200) self.send_header("Content-type", "text/html; charset=utf-8") self.end_headers() def do_GET(self): self.send_response(200) self.send_header("Content-type", "text/html; charset=utf-8") self.end_headers() url = urlparse.urlsplit(self.path) print url.path if url.path == '/frame_a.html': ip, port = self.headers.get('Host').split(":", 2) self.wfile.write(PAGE_TEMPLATE_A % ip) elif url.path == '/frame_b.html': self.wfile.write(PAGE_TEMPLATE_B) else: self.wfile.write(PAGE_TEMPLATE) def do_POST(self): self.send_response(200) self.send_header("Content-type", "text/plain; charset=utf-8") self.end_headers() if self.path.startswith("/command/"): try: #/command/state:up state, cmd = self.path.split("/")[-1].split(":") except ValueError: print "ERROR", self.path self.wfile.write("fail") return controller.update_state(state, cmd) self.wfile.write("ok") elif self.path.startswith("/ping"): self.wfile.write("pong") controller = CarControllerThread(COMMAND_TIMEOUT) controller.start() try: droid.wakeLockAcquireBright() droid.webcamStart(0, 10, 9091) droid.webcamAdjustQuality(0, 10) except Exception as e: print "Webcam error", e my_srv = BaseHTTPServer.HTTPServer((HOST_NAME, PORT_NUMBER), DroidHandler) print 'web server running on port %s' % PORT_NUMBER my_srv.serve_forever()
Отредактировано Nikoil (Март 4, 2013 12:35:05)
Офлайн
Забавная штука. Как раз хотел под Android что-нибудь написать.
https://gist.github.com/reclosedev/5064616
Файлы из Sound command v02.rar в path_to_audio = ‘/mnt/sdcard/droid_car/’
скрипт в /mnt/sdcard/sl4a/scripts/
Как в виде .apk распространять не знаю, но вроде есть способы.
Офлайн
Даже не знаю как описать на сколько я рад
Есть потери некоторых звуков - но я сделаю их немножко длинней и одинаковыми по времени воспроизведения и сдлеаю инструкцию с видеообзором на 4pda.
Для апк это не подойдет - но как версия для управления с пк отличный вариант.
Еще раз спасибо.
Офлайн
Сдел видео.Звук играет несколко циклов хорошо, а потом интервал. Несколько циклов и интервал.Повторяется на всех командах.
http://www.youtube.com/watch?v=uoGBsIYU5Zk&feature=youtu.be
Это можно исправить?
Отредактировано Nikoil (Март 2, 2013 19:39:28)
Офлайн
Похоже, баг Android
https://code.google.com/p/android/issues/detail?id=18756
Кстати, скиньте новые аудио файлы.
Отредактировано reclosedev (Март 2, 2013 20:42:10)
Офлайн
http://4pda.ru/forum/dl/post/2633134/Sound+command+v03.rar
А если звуковой файл сдлеть длинней примерно 20 секунд с цикличностью (первые 2-3 прокрутки идут без задержки) А действия сделать так:
действие нажал кнопку - трек играет по кругу , а функция отпустил кнопку - стоп воспроизведения трека.
(и команд будет передаваться меньше 1ая start play 2ая stop play) и нагрузка на android меньше.
Это как вариант.Т.к. может быть такое что одна из команд не дойдет до устройства.
Отредактировано Nikoil (Март 2, 2013 21:52:34)
Офлайн
NikoilДа это поможет, но между этими N секундами интервал все равно останется. Думаю 20 сек много, файл 2 МБ получается, может и 10 секунд хватит для команды?
А если звуковой файл сдлеть длинней примерно 20 секунд с цикличностью (первые 2-3 прокрутки идут без задержки)
NikoilСначала так и сделал.
А действия сделать так:
действие нажал кнопку - трек играет по кругу , а функция отпустил кнопку - стоп воспроизведения трека.
(и команд будет передаваться меньше 1ая start play 2ая stop play) и нагрузка на android меньше.
NikoilДа, по Wi-fi команды могут теряться (при тестах терялись). Именно поэтому команда и передается с некоторым интервалом, пока кнопка нажата, чтобы можно было отличить потерю команды стоп от очень долгого нажатия.
Это как вариант.Т.к. может быть такое что одна из команд не дойдет до устройства.
Отредактировано reclosedev (Март 3, 2013 09:24:38)
Офлайн
Работает лучше.Звуковые файлы по 10 секунд.На неделе протестирую на практике( с платформой)
Офлайн
Заметил проблему.Сбит центр джойстика - прикрепил фото №1.(код в шапке заменил на ваш с моими маленькими изменениями)
Убрал прокрутку в видео окне. Отцентровал кнопки управления и окно видео.
——————–
И что если сделать iframe по вертикали?Сделал набросок на фото.
При таком расположении станет удобно управлять даже с телефона, а на пк тач панель просто можно свернуть в ручную если будет мешать .Левое окно как вариант в авто масштаб.Только вот кнопки управления up,down,left,right нужно будет переместить из iframe B в iframe A.
Отредактировано Nikoil (Март 4, 2013 13:03:57)
Прикреплённый файлы: 1.jpg (112,3 KБ)
Офлайн
NikoilДа тоже видел. virtualjoystick.js ориентируется на координаты страницы, а не контейнера. Поэтому нужно или код менять (что не хочется) или в iframe его засовывать (сделал).
Заметил проблему.Сбит центр джойстика - прикрепил фото №1.(код в шапке заменил на ваш с моими маленькими изменениями)
Убрал прокрутку в видео окне. Отцентровал кнопки управления и окно видео.
NikoilСделал без фреймов, т.к. с ними геморой.
И что если сделать iframe по вертикали?Сделал набросок на фото.
При таком расположении станет удобно управлять даже с телефона, а на пк тач панель просто можно свернуть в ручную если будет мешать .Левое окно как вариант в авто масштаб.Только вот кнопки управления up,down,left,right нужно будет переместить из iframe B в iframe A.
Офлайн