- •Содержание
- •Введение
- •1 Анализ исходных данных
- •2 Программное проектирование
- •3 Программная реализация
- •3.1 Детальная реализация функциональных частей по
- •Проверяем время записи и наличие данных в очереди. Извлекаем данные из очереди и записываем в файл. Уменьшаем счетчик размера очереди. Процесс повторяется вновь при помощи цикла while.
- •3.2 Сопроводительная документация по
- •3.3 Анализ по
- •3.4 Тестирование по
- •Заключение
- •Список использованных источников
- •Приложения Приложение а
- •Техническое задание
- •1 Назначение, цели и задачи разработки
3 Программная реализация
Описание и проектирование программы, а также выбор языка программирования и библиотек выполнено. Теперь, непосредственно, можно приступать к реализации программы скрытого наблюдения.
3.1 Детальная реализация функциональных частей по
Для начала подключим функцию обратного вызова к потоку аудио ввода. Для этого необходимо указать следующие параметры:
samplerate – частота дискретизации;
device – идентификатор аудиоустройства в системе;
channels – количество каналов для записи;
callback – имя функция обратного вызова для обработки получаемых данных.
Для этих параметров создадим глобальные переменные с аналогичными названиями. Также предусмотрим возможность не указывать частоту дискретизации, в таком случае будет задано значение по умолчанию для данного устройства.
Листинг 3.1 – Задание параметров потока аудио ввода
if samplerate is None:
device_info = sd.query_devices(device, 'input')
samplerate = int(device_info['default_samplerate'])
with sd.InputStream(samplerate=samplerate, device=device,
channels=channels, callback=callback):
logging.info('Listening...')
print('Listening...')
Далее необходимо создать саму функцию обратного вызова. Функция имеет следующие параметры:
indata – аудиоданные;
frames – количество кадров;
time – словарь со следующими ключами: input_buffer_adc, current_time и output_buffer_dac_time (значения см. в документации PortAudio);
status – один из флагов обратного вызова (значения см. в документации PortAudio).
Данные будут сохраняться в очередь записи. Здесь необходимо предусмотреть задание времени записи, ограничение максимального времени записи и подсчет количества данных в очереди. Создадим для них глобальные переменные: timeout, max_timeout, qsize. Для запуска записи измерим уровень громкости и сравним с порогом акустопуска. Для порога акустопуска создадим глобальную переменную trigger.
Листинг 3.2 – Функция обратного вызова
def callback(indata, frames, time, status):
global timeout, max_timeout, qsize
volume = numpy.linalg.norm(indata) * 100
if volume > trigger:
timeout = t.time() + record_seconds
if max_timeout == 0:
max_timeout = t.time() + max_record_seconds
if t.time() < timeout and t.time() < max_timeout:
q.put(indata.copy())
qsize += 1
else:
timeout = 0
max_timeout = 0
Теперь приступим к записи файлов. Проверив наличие данных в очереди для записи, убедимся в существовании папки с текущей датой, в которую будет записывать аудиофайлы. Если папка отсутствует – создаем. После этого создаем звуковой файл для чего необходимо указать следующие параметры:
path – путь к файлу, включая его имя и расширение;
mode – режим записи файла;
sfinfo – структура в которой задаются параметры аудио файла.
Проверяем время записи и наличие данных в очереди. Извлекаем данные из очереди и записываем в файл. Уменьшаем счетчик размера очереди. Процесс повторяется вновь при помощи цикла while.
Листинг 3.3 – Запись аудиофайла
while True:
if qsize > 0:
now = dt.datetime.now()
folder = now.strftime('%Y-%m-%d')
if not os.path.isdir(folder)
os.mkdir(folder)
os.chdir(folder)
filename = now.strftime('%Y-%m-%d %H-%M-%S.wav')
with sf.SoundFile(filename, mode='x',
samplerate=samplerate,
channels=channels, subtype=subtype) as file:
logging.info('Recording started: ' +
repr(filename))
print('Recording started: ' + repr(filename))
while t.time() < timeout or qsize > 0:
if qsize > 0:
file.write(q.get())
qsize -= 1
logging.info('Recording finished: ' +
repr(filename))
print('Recording finished: ' + repr(filename))
os.chdir("..")
При запуске программы добавим проверку на наличие конфигурационного файла. При наличии его будет производиться чтение параметров с записью в глобальные переменные. При его отсутствии будет создан новый с значениями по умолчанию. Значения по умолчанию будем записывать следующие:
Таблица 3.1 – Значения по умолчанию для файла конфигурации
Название параметра |
Значение |
device |
0 |
samplerate |
None |
channels |
1 |
subtype |
‘PCM_24’ |
record_seconds |
10 |
max_record_seconds |
600 |
trigger |
50 |
log_level |
20 |
Листинг 3.4 – Создание и чтение файла конфигурации
if os.path.exists('settings.ini'):
config = cp.ConfigParser()
config.read('settings.ini')
# читаем значения из конфиг. файла
device = int(config.get('settings', 'device'))
samplerate = config.get('settings', 'samplerate')
channels = int(config.get('settings', 'channels'))
subtype = config.get('settings', 'subtype')
record_seconds = int(config.get('settings',
'record_seconds'))
max_record_seconds = int(config.get('settings',
'max_record_seconds'))
trigger = int(config.get('settings', 'trigger'))
log_level = int(config.get('settings', 'log_level'))
if samplerate == 'None':
samplerate = None
else:
samplerate = int(samplerate)
else:
logging.warning('Error opening the settings file')
print('Error opening the settings file')
config = cp.ConfigParser()
config.add_section('settings')
config.set('settings', 'device', str(device))
config.set('settings', 'samplerate', str(samplerate))
config.set('settings', 'channels', str(channels))
config.set('settings', 'subtype', str(subtype))
config.set('settings', 'record_seconds',
str(record_seconds))
config.set('settings', 'max_record_seconds',
str(max_record_seconds))
config.set('settings', 'trigger', str(trigger))
config.set('settings', 'log_level', str(log_level))
with open('settings.ini', "w") as config_file:
config.write(config_file)