#include #include #include #include #include #include #include #include #define ABS(x) ((x) < 0 ? -(x) : (x)) #define NUM "4" void dummyhandler (struct context * rc, float * samples, int samples_num, enum action) { // does nothing } enum action { kys, // this is the last time function will be called, free handler data and NULL it dtmf_1, dtmf_2, dtmf_3, dtmf_4, dtmf_5, dtmf_6, dtmf_7, dtmf_8, dtmf_9, dtmf_0, dtmf_a, dtmf_b, dtmf_c, dtmf_d, dtmf_zvezdica, dtmf_lojtra, band, spodnja, zgornja, oranžna, plava }; enum state { silence, // initial state, waiting on line for relation. when changing to silence, kill handler. carrier, forbidden, // dtmf # detected called, // set immediately if calling number is empty nonsense, // set if menu handler doesn't understand and we shouldn't respond handler, // call handler on every action playing // ptt is held down and samples are being sent }; struct context { double glasnost; // delete unsigned roger1; // micros when roger1 was received. when roger2 is received and this time is less than 1000, roger was completely received. if this is greater than 1000, reset to 0 indicating no roger1 was present. on completely received roger, kill handler and switch to playing state. switch to playing state only upon completely hearing roger. enum state state; double * samples; // samples to play unsigned samples_length; // when playing, if samples_length is longer than 60 seconds, cut playback for safety -- we could do this in hardware as well. unsigned eot; // micros when transmission will be over and we have to release PTT void * handler_data; // assert that it's NULL after sending kys to handler }; static enum SoundIoFormat prioritized_formats[] = { // SoundIoFormatFloat32FE, ///SoundIoFormatS32NE, // SoundIoFormatS32FE, ///SoundIoFormatS24NE, // SoundIoFormatS24FE, // SoundIoFormatS16NE, // SoundIoFormatS16FE, // SoundIoFormatFloat64NE, // SoundIoFormatFloat64FE, ///SoundIoFormatU32NE, // SoundIoFormatU32FE, ///SoundIoFormatU24NE, // SoundIoFormatU24FE, // SoundIoFormatU16NE, // SoundIoFormatU16FE, ///SoundIoFormatS8, ///SoundIoFormatU8, SoundIoFormatInvalid }; static void read_callback (struct SoundIoInStream * instream, int frame_count_min __attribute__((unused)), int frame_count_max) { struct context * rc = instream->userdata; struct SoundIoChannelArea * areas; int frame_count = frame_count_max; int err = soundio_instream_begin_read(instream, &areas, &frame_count); long long vzorcev = 0; double glasnost = 0; if (!frame_count) return; if (!areas) // HOLE because of overrun! -- kill handler and change to silence/initial state rc->glasnost = 0; else for (int frame = 0; frame < frame_count; frame++) for (int ch = 0; ch < instream->layout.channel_count; ch++) { glasnost += ABS(* (float *) areas[ch].ptr); vzorcev++; areas[ch].ptr += areas[ch].step; } rc->glasnost = glasnost / vzorcev; if ((err = soundio_instream_end_read(instream))) error_at_line(0, 0, __FILE__, __LINE__, "soundio_instream_read_end: %s", soundio_strerror(err)); } static void overflow_callback (struct SoundIoInStream * instream __attribute__((unused))) { static int count = 0; fprintf(stderr, "overflow %d\n", ++count); } static void error_callback (struct SoundIoInStream * instream __attribute__((unused)), int err) { fprintf(stderr, "error %s\n", soundio_strerror(err)); // TODO this is unrecoverable, make exit of program } int main (void) { struct SoundIoInStream * instream = NULL; struct SoundIoDevice * selected_device = NULL; int r = 0; fprintf(stderr, "z okoljsko spremenljivko ID nastaviš id naprave -- idje izpiše program naprave\nz okoljsko spremenljivko ZALEDJE nastaviš zaledje -- program naprave izpiše možna zaledja\n"); enum SoundIoBackend backend = SoundIoBackendNone; char * device_id = getenv("ID"); if (getenv("ZALEDJE")) { switch (getenv("ZALEDJE")[0]) { case 'd': backend = SoundIoBackendDummy; break; case 'a': backend = SoundIoBackendAlsa; break; case 'p': backend = SoundIoBackendPulseAudio; break; case 'j': backend = SoundIoBackendJack; break; case 'c': backend = SoundIoBackendCoreAudio; break; case 'w': backend = SoundIoBackendWasapi; break; } } struct SoundIo * soundio = soundio_create(); if (!soundio) error_at_line(1, ENOMEM, __FILE__, __LINE__, "soundio_create()"); int err = (backend == SoundIoBackendNone) ? soundio_connect(soundio) : soundio_connect_backend(soundio, backend); if (err) { error_at_line(0, 0, __FILE__, __LINE__, "soundio_connect: %s", soundio_strerror(err)); r = 2; goto r; } soundio_flush_events(soundio); if (device_id) { for (int i = 0; i < soundio_input_device_count(soundio); i++) { struct SoundIoDevice * device = soundio_get_input_device(soundio, i); if (!strcmp(device_id, device->id)) { selected_device = device; break; } soundio_device_unref(device); } } else { int device_index = soundio_default_input_device_index(soundio); selected_device = soundio_get_input_device(soundio, device_index); } if (!selected_device) { error_at_line(0, 0, __FILE__, __LINE__, "!selected_device"); r = 3; goto r; } fprintf(stderr, "izbrana naprava je %s\n", selected_device->name); if (selected_device->probe_error) { error_at_line(0, 0, __FILE__, __LINE__, "unable to probe device: %s", soundio_strerror(selected_device->probe_error)); r = 4; goto r; } soundio_device_sort_channel_layouts(selected_device); // TODO poskusi brez int sample_rate = 0; for (int i = 0; i < selected_device->sample_rate_count; i++) { if (44100 <= selected_device->sample_rates[i].max && 44100 >= selected_device->sample_rates[i].min) sample_rate = 44100; } if (!sample_rate) { error_at_line(0, 0, __FILE__, __LINE__, "naprava ne podpira vzorčenja na željeni frekvenci"); r = 5; goto r; } if (!selected_device->format_count) { error_at_line(0, 0, __FILE__, __LINE__, "naprava ne podpira oblik"); r = 6; goto r; } enum SoundIoFormat fmt = SoundIoFormatInvalid; for (unsigned i = 0; i < sizeof prioritized_formats/sizeof prioritized_formats[0]; i++) { if (soundio_device_supports_format(selected_device, prioritized_formats[i])) { fmt = prioritized_formats[i]; break; } } if (fmt == SoundIoFormatInvalid) { // fmt = selected_device->formats[0]; error_at_line(0, 0, __FILE__, __LINE__, "naprava ne podpira podprte oblike"); r = 7; goto r; } instream = soundio_instream_create(selected_device); if (!instream) { error_at_line(0, 0, __FILE__, __LINE__, "oom"); r = 8; goto r; } // sample_rate = 8000; fprintf(stderr, "hitrost vzorčenja je %d Hz, %s (prepleten)\n", sample_rate, soundio_format_string(fmt)); instream->format = fmt; instream->sample_rate = sample_rate; instream->read_callback = read_callback; instream->overflow_callback = overflow_callback; instream->error_callback = error_callback; struct context rc = { 0 }; instream->userdata = &rc; if ((err = soundio_instream_open(instream))) { error_at_line(0, 0, __FILE__, __LINE__, "soundio_instream_open: %s (%d)", soundio_strerror(err), err); r = 9; goto r; } if (instream->bytes_per_sample != 4) { error_at_line(0, 0, __FILE__, __LINE__, "nisem pričakoval vzorcev, velikih po %d bajtov", instream->bytes_per_sample); r = 10; goto r; } fprintf(stderr, "pretok: %s\n", instream->layout.name); if ((err = soundio_instream_start(instream))) { error_at_line(0, 0, __FILE__, __LINE__, "soundio_instream_start: %s", soundio_strerror(err)); r = 11; goto r; } int najv_gl = 1; int leds[] = { open("/sys/class/leds/input" NUM "::numlock/brightness", O_WRONLY), open("/sys/class/leds/input" NUM "::capslock/brightness", O_WRONLY), open("/sys/class/leds/input" NUM "::scrolllock/brightness", O_WRONLY) }; while (1) { soundio_flush_events(soundio); usleep(10000); if (rc.glasnost > najv_gl) najv_gl = rc.glasnost; if (najv_gl < 1) najv_gl = 1; printf("glasnost: "); for (int i = 0; i < 64; i++) if (((double) rc.glasnost/najv_gl)*64 > i) printf("@"); else printf(" "); if ((double) rc.glasnost/najv_gl > 0.2) write(leds[0], "1", 1); else write(leds[0], "0", 1); if ((double) rc.glasnost/najv_gl > 0.5) write(leds[1], "1", 1); else write(leds[1], "0", 1); if ((double) rc.glasnost/najv_gl > 0.7) write(leds[2], "1", 1); else write(leds[2], "0", 1); printf("\n"); if (rc.glasnost < najv_gl/2) najv_gl -= 5; } r: if (instream) soundio_instream_destroy(instream); if (selected_device) soundio_device_unref(selected_device); soundio_destroy(soundio); return r; }