2012-04-25 2 views
3

Я работаю над созданием приложения, которое позволяет общаться с очень низкой пропускной способностью через высокочастотные звуковые волны. Я дошел до того, что могу создать частоту и сделать преобразование Фурье (с помощью открытого кода Moonblink для Audalyzer).Android - Планирование событий каждые 10 мс?

Но вот моя проблема: я не могу заставить код работать с правильным временем. Предположим, я хочу, чтобы часть кода выполнялась каждые 10 мс, как я могу это сделать?

Я пробовал использовать TimerTask, но перед выполнением кода, как и до 100 мс, существует огромная задержка.

Я также пробовал этот метод просто путем проверки текущего времени и выполнения только тогда, когда это время истекло. Но есть проблема с задержкой. У вас есть идеи?

Thread analysis = new Thread(new Runnable() 
{ 
    @Override 
    public void run() 
    { 
     android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY); 

     long executeTime = System.currentTimeMillis(); 

     manualAnalyzer.measureStart(); 
     while (FFTransforming) 
     {   
      if(System.currentTimeMillis() >= executeTime) 
      { 
       //Reset the timer to execute again in 10ms 
       executeTime+=10; 

       //Perform Fourier Transform 
       manualAnalyzer.doUpdate(0); 

       //TODO: Analyze the results of the transform here... 

      } 
     } 
     manualAnalyzer.measureStop(); 
    } 
}); 
analysis.start(); 
+0

Вы пробовали поставить executeTime = System.currentTimeMillis() + 10; после doUpdate()? Таким образом, вы должны установить точную задержку в 10 мс между doUpdates – Renard

+0

Я попытался это сделать, однако, поскольку текущее время иногда превышает время выполнения (из-за сбора мусора и других потоков), он не может возникать с точным шагом в 10 мс , И поскольку я пытаюсь синхронизировать с другим устройством, которое ожидает эти точные приращения, оно не работает полностью. – YasharBahman

+0

, если у вас есть контроль над всем кодом, вы также можете попытаться устранить сбор мусора, используя диспетчер выделения и предварительно распределив все ваши объекты. также обратите внимание, что если вы получите всплеск в doUpdate, который длиннее 10 мс, время будет отключено. – Renard

ответ

1

Ваша стратегия ниток/петли, вероятно, примерно такая же близкая, как вы собираетесь. Однако 10 мс не так много времени, большинство устройств Android не супермощны, а преобразование Фурье - это большая работа. Я считаю маловероятным, что вы сможете приспособить эту работу в 10 мс. Я подозреваю, что вам придется увеличить этот период.

+0

Я приурочил его, и преобразование Фурье обычно происходит при 1 мс (обычно около 300 мкс). Тем не менее, сбор мусора и другие потоки, время может быть отброшено. Я знаю, что я мог бы установить приоритет потока с наивысшим приоритетом (-20 согласно документации), но по какой-то причине я чувствую, что это плохая практика. Как вы думаете? – YasharBahman

+0

Интересно, я немного удивлен, что вы можете получить его так быстро, но если он работает, он работает. Если действительно важно, что вы сможете получить 10 мс прирост, я бы не подумал, что это плохо, чтобы дать первому приоритету потока. Можете ли вы обычно получать 10 мс интервалов, но иногда получаете всплески? – kabuko

+0

Честно говоря, он работает. Но опять же, я запускаю его на Galaxy Nexus, поэтому у него есть преимущество над более старыми телефонами, что плохо. И да, я получаю случайный всплеск. Ренард упомянул об устранении сбора мусора, что, вероятно, смягчит эту проблему. Вы знаете другой метод? Или существует способ жестко применять TimerTask? – YasharBahman

1

Я изменил код, чтобы он учитывал время выполнения doUpdate. Использование System.nanoTime() также должно повысить точность.

public void run() { 
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY); 

long executeTime=0;   
long nextTime = System.nanoTime(); 

manualAnalyzer.measureStart(); 
while (FFTransforming) 
{   
    if(System.nanoTime() >= nextTime) 
    { 
     executeTime = System.nanoTime(); 
     //Perform Fourier Transform 
     manualAnalyzer.doUpdate(0); 
     //TODO: Analyze the results of the transform here... 
     executeTime = System.nanoTime() - executeTime; 
     //guard against the case that doUpdate took longer than 10ms 
     final long i = executeTime/10000000; 
     //set the timer to execute again at the next full 10ms intervall 
     nextTime+= 10000000+ i*10000000 
    } 
} 
manualAnalyzer.measureStop(); 
    } 

Что еще вы могли бы сделать?

  • устранения мусора Коллекция
  • пойти родным с NDK (только идея, это не могло бы также дать никакой пользы)
+0

Это хорошая идея. Было бы проблематично, если бы я пропустил цикл, но остальная часть данных была бы повреждена. Но, по крайней мере, с помощью этого метода я могу это обнаружить. – YasharBahman

+0

(случайно отправлено слишком рано) И, как вы сказали выше, единственный способ устранить сбор мусора - избежать выделения. Было бы неплохо позвонить в System.gc(), когда я знаю, что у меня есть время сделать это? Таким образом, я встречаюсь не так часто. Или все еще будет так же часто? – YasharBahman

+0

Невозможно сказать. Я видел эту практику раньше, но если вы будете много выделять во время фрейм-времени, gc в конечном итоге произойдет. Также я думаю, что ответ [Chris Strattons] (http://stackoverflow.com/users/429063/chris-stratton) будет лучшим решением ваших проблем :-) – Renard

2

Я рекомендовал бы совершенно другой подход: Не пытайтесь запустить ваш код в реальном времени.

Вместо этого полагайтесь только на низкоуровневый звуковой код, работающий в реальном времени, путем записи (или воспроизведения) непрерывно в течение определенного периода времени, охватывающего события, представляющие интерес.

Затем ваш код выполняется несколько асинхронно, разделенный аудио буферами. Чувство времени вашего кода определяется не системными часами по мере его выполнения, а скорее определенным интервалом между выборками аудиоданных, с которыми вы работаете. (т. е. если вы используете 48 Ksps, то 10 мс позже - 480 образцов позже)

Возможно, вам потребуется изменить протокол, регулирующий взаимодействие между устройствами, чтобы расширить окно времени, в котором можно ожидать передачи. То есть, вы можете иметь точное время относительно фактической модуляции и символов внутри «пакета», но вы не должны ожидать почти того же порядка точности при определении того, когда пакет отправлен или получен - вам придется «найти» его среди более длинной записи, содержащей шум.

+0

Это хорошая идея, но я не могу понять как бы синхронизировать телефоны вместе. Потому что я использую аудиопоток, так как я собираюсь загружать данные, динамически зависящие от того, какие данные нужно отправить. Затем играйте, когда он готов. И я не думаю, что есть способ сказать, когда звуковой буфер пуст. Кроме того, даже если бы я мог получить какую-то функцию обратного вызова для выполнения после того, как будет воспроизводиться каждый образец, это необязательно будет называться мгновенным завершением, оно будет вызываться, как только планировщик решает, не так ли? – YasharBahman

+0

И даже если бы это произошло, не потребовалось бы некоторое неизвестное количество времени, чтобы снова загрузить буфер и начать играть? Сообщите мне, если я не понимаю. – YasharBahman

+0

Вам нужно будет посмотреть, как получить минимальный латентный звук, да. Что еще более важно, вам нужно будет разработать протокол для более длинных оборотных окон между передачей и ожиданием подтверждения. Вы можете закончить запись непрерывно, так как телефон, вероятно, достаточно быстр, чтобы обрабатывать данные, ищущие сигналы, он просто не может надежно сделать это в нужный момент. У некоторых буферов вы покупаете толерантность - данные записываются или создаются с точным временем, но обработка может произойти немного рано или поздно, пока среднее значение сохраняется. –

Смежные вопросы