2021-01-15 16:15:58 -05:00
|
|
|
/*
|
|
|
|
* Audio Library for Linux and Windows
|
|
|
|
* ===================================
|
|
|
|
* Author: DJ0ABR
|
|
|
|
*
|
|
|
|
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
|
|
|
|
* License: GPL-3
|
|
|
|
*
|
|
|
|
* compilation:
|
|
|
|
* Windows ... Visual Studio
|
|
|
|
* Linux ... make
|
|
|
|
*
|
|
|
|
* Documentation see: libkmaudio.h
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*
|
|
|
|
* libkmaudio_capture.cpp ...
|
|
|
|
* starts a libsoundio capture stream and a callback routine. Writes the
|
|
|
|
* received audio samples into the fifo (Linux only)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
|
|
|
|
#include "libkmaudio.h"
|
|
|
|
|
|
|
|
char* getDevID(char* devname, int io, int *pidx)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < devanz; i++)
|
|
|
|
{
|
|
|
|
//printf("%s: %d %d\n", devlist[i].name, io, devlist[i].in_out);
|
|
|
|
if (!strcmp(devname, devlist[i].name) && io == devlist[i].in_out)
|
|
|
|
{
|
|
|
|
*pidx = i;
|
|
|
|
return devlist[i].id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int min_int(int a, int b)
|
|
|
|
{
|
|
|
|
return (a < b) ? a : b;
|
|
|
|
}
|
|
|
|
|
|
|
|
void read_callback(struct SoundIoInStream* instream, int frame_count_min, int frame_count_max)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
if (instream == NULL || soundio == NULL) return;
|
|
|
|
//printf("cap: %d %d\n", frame_count_min, frame_count_max);
|
|
|
|
//int chans = instream->layout.channel_count;
|
|
|
|
//printf("cap:%d\n", instream->sample_rate);
|
|
|
|
int idx = *((int *)(instream->userdata));
|
|
|
|
|
|
|
|
struct SoundIoChannelArea* areas;
|
|
|
|
// samples are in areas.ptr
|
|
|
|
int frames_left = frame_count_max; // take all
|
2021-02-22 09:58:19 -05:00
|
|
|
while (keepcallbacksrunning)
|
2021-01-15 16:15:58 -05:00
|
|
|
{
|
|
|
|
int frame_count = frames_left;
|
|
|
|
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
|
|
|
|
{
|
|
|
|
fprintf(stderr, "begin read error: %s", soundio_strerror(err));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!frame_count)
|
|
|
|
break;
|
|
|
|
|
|
|
|
//printf("write %d samples to fifo %d. Channels:%d\n", frame_count, idx, instream->layout.channel_count);
|
|
|
|
for (int frame = 0; frame < frame_count; frame += 1)
|
|
|
|
{
|
|
|
|
for (int ch = 0; ch < instream->layout.channel_count; ch += 1)
|
|
|
|
{
|
|
|
|
float frxdata;
|
|
|
|
memcpy(&frxdata, areas[ch].ptr, instream->bytes_per_sample);
|
|
|
|
areas[ch].ptr += areas[ch].step;
|
|
|
|
if (ch == 0)
|
|
|
|
{
|
|
|
|
io_write_fifo(idx, frxdata);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//measure_speed_bps(frame_count);
|
|
|
|
|
|
|
|
if ((err = soundio_instream_end_read(instream)))
|
|
|
|
{
|
|
|
|
printf("end read error: %s", soundio_strerror(err));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
frames_left -= frame_count;
|
|
|
|
if (frames_left <= 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void overflow_callback(struct SoundIoInStream* instream)
|
|
|
|
{
|
|
|
|
static int count = 0;
|
|
|
|
printf("overflow %d\n", ++count);
|
|
|
|
}
|
|
|
|
|
2021-01-18 09:36:29 -05:00
|
|
|
void close_capture_stream(int idx)
|
|
|
|
{
|
|
|
|
if (devlist[idx].instream != NULL)
|
|
|
|
{
|
|
|
|
soundio_instream_destroy(devlist[idx].instream);
|
|
|
|
devlist[idx].instream = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-15 16:15:58 -05:00
|
|
|
int kmaudio_startCapture(char* devname, int samprate)
|
|
|
|
{
|
|
|
|
printf("Start request for CAP stream:%s\n", devname);
|
|
|
|
|
|
|
|
if (devname == NULL || strlen(devname) < 3) // no devices defined yet
|
|
|
|
{
|
|
|
|
printf("no capture devices specified\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int idx = 0; // index into devlist
|
|
|
|
char* capdevid = getDevID(devname, 0, &idx);
|
|
|
|
if (capdevid == NULL) return -1;
|
|
|
|
|
|
|
|
// if an old stream is open, close it
|
2021-01-18 09:36:29 -05:00
|
|
|
close_capture_stream(idx);
|
|
|
|
|
2021-01-15 16:15:58 -05:00
|
|
|
printf("Starting CAP stream:%s [%d]\n", devname, idx);
|
|
|
|
|
|
|
|
io_fifo_clear(idx);
|
|
|
|
|
|
|
|
devlist[idx].working = 0;
|
|
|
|
|
|
|
|
// define the capture device
|
|
|
|
soundio_flush_events(soundio);
|
|
|
|
|
|
|
|
for (int i = 0; i < soundio_input_device_count(soundio); i++)
|
|
|
|
{
|
|
|
|
devlist[idx].io_cap_device = NULL;
|
|
|
|
struct SoundIoDevice* device = soundio_get_input_device(soundio, i);
|
|
|
|
if (strcmp(device->id, capdevid) == 0)
|
|
|
|
{
|
|
|
|
devlist[idx].io_cap_device = device;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
soundio_device_unref(device);
|
|
|
|
}
|
|
|
|
if (!devlist[idx].io_cap_device)
|
|
|
|
{
|
|
|
|
printf("Invalid device id: %s\n", capdevid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devlist[idx].io_cap_device->probe_error)
|
|
|
|
{
|
|
|
|
printf("Unable to probe device: %s\n", soundio_strerror(devlist[idx].io_cap_device->probe_error));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create capture callback
|
|
|
|
devlist[idx].instream = soundio_instream_create(devlist[idx].io_cap_device);
|
|
|
|
if (!devlist[idx].instream) {
|
|
|
|
printf("capture: out of memory\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
devlist[idx].requested_samprate = samprate;
|
|
|
|
if (getRealSamprate(idx) == -1)
|
|
|
|
{
|
|
|
|
printf("Samplerate %d not supported by device:<%s>\n", samprate, devname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devlist[idx].requested_samprate != devlist[idx].real_samprate)
|
|
|
|
resampler_create(idx);
|
|
|
|
|
|
|
|
devlist[idx].instream->format = SoundIoFormatFloat32NE;
|
|
|
|
devlist[idx].instream->sample_rate = devlist[idx].real_samprate;
|
|
|
|
devlist[idx].instream->software_latency = 0.1f;
|
|
|
|
devlist[idx].instream->read_callback = read_callback;
|
|
|
|
devlist[idx].instream->overflow_callback = overflow_callback;
|
|
|
|
devlist[idx].instream->userdata = &(devlist[idx].index);
|
|
|
|
|
|
|
|
int err = 0;
|
|
|
|
if ((err = soundio_instream_open(devlist[idx].instream))) {
|
|
|
|
printf("unable to open input stream: %d: %s", err, soundio_strerror(err));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((err = soundio_instream_start(devlist[idx].instream))) {
|
|
|
|
printf("unable to start input device: %s", soundio_strerror(err));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("selected CAPTURE device:\nname:%s\nid :%s\n", devlist[idx].name, capdevid);
|
|
|
|
printf("physical capture rate:%d, requested capture rate:%d\n", devlist[idx].real_samprate, devlist[idx].requested_samprate);
|
|
|
|
printf("format: %s\n\n", soundio_format_string(devlist[idx].instream->format));
|
|
|
|
|
|
|
|
devlist[idx].working = 1;
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // #ifndef WIN32
|