Изучив исходный код программы beep
, я придумал минимальную программу на языке C, которая звонит в колокольчик.
Он использует динамик ПК, который ядро Linux делает доступным как устройство evdev, обычно называемое/dev/input/by-path/platform-pcspkr-event-spkr
(символической ссылкой на фактическое местоположение ).
Существует одно событие для включения динамика (, т.е. для начала воспроизведения звука )на заданной частоте, и другое событие для выключения динамика (, т.е. для остановки звука ). Мы просто отправляем первое событие, затем спим необходимое время, затем отправляем второе событие.
Для этого требуется доступ на запись к устройству, который можно настроить с помощью правила udev, бита setuid для программы или запуска программы от имени пользователя root, как описано в документации beep
. Кроме того, это не может контролировать громкость звука. Почему-то программа xset
(из комплекта X-серверов )и эмуляторы терминала не имеют этих ограничений.
#include // struct input_event
#include // open
#include // write, close
#include // nanosleep
/* frequency (Hz): */
static unsigned int const default_frequency = 440;
/* duration (ms): */
static unsigned int const default_duration = 200;
/* file path of PC speaker: */
static char const * const default_device = "/dev/input/by-path/platform-pcspkr-event-spkr";
void start_beep(int fd, int freq)
{
struct input_event e = { 0 };
e.type = EV_SND;
e.code = SND_TONE;
e.value = freq;
write(fd, &e, sizeof(e));
}
void stop_beep(int fd)
{
start_beep(fd, 0);
}
void sleep_ms(unsigned int ms)
{
struct timespec duration =
{.tv_sec = ms / 1000U,
.tv_nsec = (long)(ms % 1000UL * 1000UL * 1000UL) };
nanosleep(&duration, NULL);
}
int main(void)
{
int fd = open(default_device, O_WRONLY);
start_beep(fd, default_frequency);
sleep_ms(default_duration);
stop_beep(fd);
close(fd);
return 0;
}
(Для краткости и ясности приведенный выше исходный код пропускает все проверки безопасности (проверяет существование файла, проверяет успешность open
, проверяет, что файловый дескриптор является символьным устройством, проверяет, что частота и продолжительность являются целыми числами в пределах допустимого диапазона, проверьте успешность write
, проверьте успешность nanosleep
… ). В реальном приложении это должно быть решено.)
Приведенную выше программу на C можно использовать для наблюдения за формой событий; затем те же события могут быть записаны из сценария оболочки. К сожалению,двоичный формат, скорее всего, зависит от платформы -. На моей машине x86 -64 с ядром Linux 5.2 звуковое событие имеет следующую структуру:
type
со значениемEV_SND
)code
со значениемSND_TONE
)value
)Эта бинарная структура может быть написана с использованием Perl с помощью функцииpack
. Двоичные целые числа также могут быть выведены с использованием чистого Bash , но это более подробно.
# frequency (Hz):
default_frequency=440
# duration (ms):
default_duration=200
# file path of PC speaker:
default_device='/dev/input/by-path/platform-pcspkr-event-spkr'
function start_beep()
{
declare -i freq="$1"
perl -e 'print pack("qqssl", 0, 0, 0x12, 2, '$freq')'
}
function stop_beep()
{
start_beep 0
}
# USAGE: beep [FREQUENCY [DURATION [DEVICE]]]
function beep()
{
declare -i freq="${1-$default_frequency}"
declare -i dur="${2-$default_duration}"
declare dev="${3-$default_device}"
# convert milliseconds to seconds
declare dur_sec=$( printf '%u.%03u' $(( dur / 1000 )) $(( dur % 1000 )) )
# write the sound events
{
start_beep $freq
sleep $dur_sec
stop_beep
} >> "$dev"
}
dd if=/dev/urandom of=file bs=1M count=400
Будет создан файл file
, который zip вообще не сможет сжать. Zip также не сможет сжимать ранее сжатые данные, включая видеофайлы.