Найти - Пользователи
Полная версия: Нужна помощь.Фунция воспроизведения wav по кругу при удерживании клавиши up на клавиатуре
Начало » Центр помощи » Нужна помощь.Фунция воспроизведения wav по кругу при удерживании клавиши up на клавиатуре
1 2
Nikoil
Нужна помощь.Нужно реализовать функцию вопроизведения звукового фала по кругу.
Пример после нажатия на кнопку клавиатуры 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()

Код взят отсюда http://www.marsohod.org/index.php/projects/plata1/205-carctrlandr
для применения в этом проекте http://4pda.ru/forum/index.php?showtopic=435445

Буду очень признателен тем кто поможет
reclosedev
Забавная штука. Как раз хотел под Android что-нибудь написать.

https://gist.github.com/reclosedev/5064616

Файлы из Sound command v02.rar в path_to_audio = ‘/mnt/sdcard/droid_car/’
скрипт в /mnt/sdcard/sl4a/scripts/

Как в виде .apk распространять не знаю, но вроде есть способы.
Nikoil
Даже не знаю как описать на сколько я рад
Есть потери некоторых звуков - но я сделаю их немножко длинней и одинаковыми по времени воспроизведения и сдлеаю инструкцию с видеообзором на 4pda.
Для апк это не подойдет - но как версия для управления с пк отличный вариант.
Еще раз спасибо.
Nikoil
Сдел видео.Звук играет несколко циклов хорошо, а потом интервал. Несколько циклов и интервал.Повторяется на всех командах.
http://www.youtube.com/watch?v=uoGBsIYU5Zk&feature=youtu.be

Это можно исправить?
reclosedev
Похоже, баг Android
https://code.google.com/p/android/issues/detail?id=18756

Кстати, скиньте новые аудио файлы.
Nikoil
http://4pda.ru/forum/dl/post/2633134/Sound+command+v03.rar

А если звуковой файл сдлеть длинней примерно 20 секунд с цикличностью (первые 2-3 прокрутки идут без задержки) А действия сделать так:
действие нажал кнопку - трек играет по кругу , а функция отпустил кнопку - стоп воспроизведения трека.

(и команд будет передаваться меньше 1ая start play 2ая stop play) и нагрузка на android меньше.

Это как вариант.Т.к. может быть такое что одна из команд не дойдет до устройства.

reclosedev
Nikoil
А если звуковой файл сдлеть длинней примерно 20 секунд с цикличностью (первые 2-3 прокрутки идут без задержки)
Да это поможет, но между этими N секундами интервал все равно останется. Думаю 20 сек много, файл 2 МБ получается, может и 10 секунд хватит для команды?
Nikoil
А действия сделать так:
действие нажал кнопку - трек играет по кругу , а функция отпустил кнопку - стоп воспроизведения трека.
(и команд будет передаваться меньше 1ая start play 2ая stop play) и нагрузка на android меньше.
Сначала так и сделал.
Nikoil
Это как вариант.Т.к. может быть такое что одна из команд не дойдет до устройства.
Да, по Wi-fi команды могут теряться (при тестах терялись). Именно поэтому команда и передается с некоторым интервалом, пока кнопка нажата, чтобы можно было отличить потерю команды стоп от очень долгого нажатия.

Т.е. сейчас, когда приходит команда, запускается зацикленное (средствами android) проигрывание файла. Если за время COMMAND_TIMEOUT секунд не приходит новая команда, воспроизведение останавливается. Если приходит та же команда, что сейчас выполняется, ничего не происходит (точнее записывается время), если приходит команда стоп, то текущее воспроизведение останавливается. Это все не должно сильно грузить android.

Но можно чуть увеличить интервал отправки команды и таймаут (см. изменения в коде, по той же ссылке), чтобы уменьшить объем передаваемых данных по сети.

Вообще, тут бы лучше подошел UDP, но тогда нужно было бы писать ГУИ клиент под несколько платформ, а браузерный даже на андроиде должен работать.
Nikoil
Работает лучше.Звуковые файлы по 10 секунд.На неделе протестирую на практике( с платформой)
Nikoil
Заметил проблему.Сбит центр джойстика - прикрепил фото №1.(код в шапке заменил на ваш с моими маленькими изменениями)
Убрал прокрутку в видео окне. Отцентровал кнопки управления и окно видео.

——————–

И что если сделать iframe по вертикали?Сделал набросок на фото.
При таком расположении станет удобно управлять даже с телефона, а на пк тач панель просто можно свернуть в ручную если будет мешать .Левое окно как вариант в авто масштаб.Только вот кнопки управления up,down,left,right нужно будет переместить из iframe B в iframe A.






reclosedev
Nikoil
Заметил проблему.Сбит центр джойстика - прикрепил фото №1.(код в шапке заменил на ваш с моими маленькими изменениями)
Убрал прокрутку в видео окне. Отцентровал кнопки управления и окно видео.
Да тоже видел. virtualjoystick.js ориентируется на координаты страницы, а не контейнера. Поэтому нужно или код менять (что не хочется) или в iframe его засовывать (сделал).

Nikoil
И что если сделать iframe по вертикали?Сделал набросок на фото.
При таком расположении станет удобно управлять даже с телефона, а на пк тач панель просто можно свернуть в ручную если будет мешать .Левое окно как вариант в авто масштаб.Только вот кнопки управления up,down,left,right нужно будет переместить из iframe B в iframe A.
Сделал без фреймов, т.к. с ними геморой.
Не стал заморачиваться с возможностью изменения размеров колонок (как у фреймов), но вроде есть решения.
Ссылка та же.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB