2010-10-25 2 views
4

У меня есть программа, которая создает поток, который захватывает данные со звуковой карты на частоте 48 кГц и записывает их в буфер для сбора. Сердце кода потока выглядит следующим образом ..Проблема с потоком Java, который захватывает данные звуковой карты

public void run() { 
    // Run continously 
    for (;;) { 
     // get data from the audio device. 
     getSample(); 
    } 
} 

// Read in 2 bytes from the audio source combine them together into a single integer 
// then write that into the sound buffer 
private void getSample() { 
    int sample,count,total=0,fsample; 
    byte buffer[]=new byte[2]; 
    try { 
      while (total<1) { 
       count=Line.read(buffer,0,2); 
       total=total+count; 
       } 
      } catch (Exception e) { 
       String err=e.getMessage(); 
      } 
    sample=(buffer[0]<<8)+buffer[1]; 

      etc etc etc 
} 

Программа работает только процесс, как представляется, взять 100% времени центрального процессора. Я полагаю, это связано с тем, что поток сидит, ожидая, когда данные поступят в строку Line.Read. Я попытался вставить Thread.yield() в разные моменты в потоке, но, похоже, не имеет значения.

Может ли кто-нибудь предложить способы уменьшить количество процессорного времени, которое занимает эта нить?

Спасибо за ваше время

Ян

ответ

3

Убедитесь, что поток заблокирован для ввода.

Поток занимает 100% от процессорного времени, если он не блокируется. Блокировка приведет к тому, что поток начнет спать, пока не появится какой-то внешний стимул, чтобы разбудить его. Всякий раз, когда у вас есть выделенный поток для обработки ввода, вам нужно убедиться, что он блокирует этот вход, чтобы он спал таким образом, чтобы избежать потока, занимающего 100% времени процессора в его цикле.

В этом конкретном случае, если Line является javax.sound.sampled.TargetDataLine, то метод read() - это то, где вы должны делать свою блокировку. Согласно API, «Этот метод блокируется до тех пор, пока не будет прочитано запрошенное количество данных», но «если линия данных закрыта, остановлена, разряжена или сброшена до того, как запрошенная сумма будет считана, этот метод больше не блокируется, но возвращает количество прочитанных байтов ».

Итак, есть пара возможностей. Я не вижу вашего определения Line, так что возможно, что вы очищаете или истощаете строку в некотором коде, который вы не указали. Если вы это сделали, вы должны реорганизовать свое решение, чтобы не использовать эти методы.

Другая возможность заключается в том, что, поскольку вы всегда читаете только два байта за раз, вы недостаточно читаете, чтобы блокировать его. В принципе, всегда есть два байта, потому что требуется слишком много времени для обработки двух прочитанных вами байтов, что всегда есть еще два байта. Попробуйте увеличить размер буфера, чтобы читать больше, как 4kb за раз. Посмотрите, что это заставляет цикл работать менее часто и блокировать чаще.

+3

Спасибо. Я модифицировал getSample() для загрузки 256 байт за раз со звуковой карты. Программа работает нормально и загрузка процессора снижается до 52%. – IanW

+0

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

+0

Вы должны экспериментировать с разными размерами и находить то, что лучше всего подходит для вашего приложения. Я не знаю, но кажется, что 256 байтов довольно малы. Пока вы получаете нужные результаты, найдите размер, который дает самую низкую нагрузку на процессор. –

0

Помещенный Thread.sleep(a few ms); в вашем бесконечном цикле, или использовать java.util.Timer для вызова getSample() каждые несколько миллисекунд.

+0

'Thread.sleep()' - способ блокировки бедных людей. Это полезно в качестве инструмента для отладки, чтобы настроить время различных вызовов, чтобы повлиять на результаты. Это плохой выбор как часть дизайна. В основном, я использовал его с EDT, чтобы дать системе момент, чтобы пропагандировать изменение пользовательского интерфейса, прежде чем я проверю статус чего-то в пользовательском интерфейсе. Как только я докажу, что он работает, я установил какой-то цикл событий-уведомлений, чтобы перезвонить. Я никогда не позволяю 'Thread.sleep()' звонить в производственный код, если нет фактической причины спать в течение определенного периода времени (например, для Планировщика). –

+0

JavaDoc: «Заставляет текущий исполняемый поток спать (временно прекратить выполнение) за указанное количество миллисекунд. Нить не теряет права собственности на какие-либо мониторы». Таким образом, у вас есть * потенциал для мертвых замков, если вы не будете осторожны, но это общая проблема с системой параллелизма Java, а другая из них я не вижу проблем с Thread.sleep() – Landei

1

Необходимо использовать буфер чтения, размер которого значительно превышает размер 2. Использование достаточно большого размера буфера практически всегда желательно в любой ситуации, но по какой-то причине javax.sound особенно неэффективен при использовании небольших размеров буфера. Я узнал об этом при внедрении VU-метра на основе Java.