277 lines
8.5 KiB
C++
Executable File
277 lines
8.5 KiB
C++
Executable File
/*
|
|
* 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
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#ifdef WIN32
|
|
// ignore senseless warnings invented by M$ to confuse developers
|
|
#pragma warning( disable : 4091 )
|
|
#pragma warning( disable : 4003 )
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <wchar.h>
|
|
|
|
#ifdef WIN32
|
|
#include "Winsock2.h"
|
|
#include "io.h"
|
|
#include <Windows.h>
|
|
#include <iostream>
|
|
#include <process.h>
|
|
#include <Tlhelp32.h>
|
|
#include <winbase.h>
|
|
#include <Shlobj.h>
|
|
#define _USE_MATH_DEFINES
|
|
#include <math.h>
|
|
#include "portaudio.h"
|
|
#include "pa_win_wasapi.h"
|
|
|
|
#pragma comment(lib, "portaudio_x86.lib")
|
|
#pragma comment(lib, "libliquid.lib")
|
|
#else
|
|
#include <sys/socket.h>
|
|
#include <unistd.h>
|
|
#include <sys/time.h>
|
|
#include <sys/ioctl.h>
|
|
#include <termios.h>
|
|
#include <sys/file.h>
|
|
#include <pthread.h>
|
|
#include <netinet/in.h>
|
|
#include <netdb.h>
|
|
#include <arpa/inet.h>
|
|
#include <pwd.h>
|
|
#include <math.h>
|
|
#include "soundio.h"
|
|
#endif
|
|
|
|
#include "liquid.h"
|
|
|
|
/*
|
|
* Sample usage:
|
|
* init sound system
|
|
* 1. kmaudio_init();
|
|
* 2. kmaudio_getDeviceList();
|
|
*
|
|
* start a capture and a playback stream
|
|
* 3. kmaudio_startCapture() using a device name returned by io_getAudioDevicelist()
|
|
* 4. kmaudio_startPlayback() using a device name returned by io_getAudioDevicelist()
|
|
*
|
|
* now everything runs in the background, no more need for the user program
|
|
* to handle sound specific data
|
|
* now we can read/write sound samples as needed by our application
|
|
* as an example: get sound from microphone and send to speaker
|
|
* process in a loop:
|
|
* 5. kmaudio_readsamples()
|
|
* 6. kmaudio_playsamples()
|
|
*
|
|
* for a working example see main(), you will need to
|
|
* replace the device names with the names in your computer
|
|
*/
|
|
|
|
/*
|
|
* initialize the audio library, create required processes
|
|
* call only once when your application starts
|
|
* returns: 0 = OK, -1 = error
|
|
*/
|
|
int kmaudio_init();
|
|
|
|
/*
|
|
* closes and frees all resources
|
|
* call only when the application exits
|
|
*/
|
|
void kmaudio_close();
|
|
|
|
/*
|
|
* read a list of all available audio devices into devlist
|
|
* the list can then be read by calling io_getAudioDevicelist()
|
|
* call any time to find new plugged in/out devices
|
|
* returns: 0=OK, -1 if error
|
|
*/
|
|
int kmaudio_getDeviceList();
|
|
|
|
/*
|
|
* starts a capturing stream from devname with samprate
|
|
* returns: id of the capture stream or -1 = error
|
|
*/
|
|
int kmaudio_startCapture(char* devname, int samprate);
|
|
|
|
/*
|
|
* starts a playback stream to devname with samprate
|
|
* returns: id of the playback stream or -1 = error
|
|
*/
|
|
|
|
int kmaudio_startPlayback(char* devname, int samprate);
|
|
|
|
/*
|
|
* plays len samples from psamp to device id
|
|
* returns: 0=ok, -1=error
|
|
* id ... device id returned by kmaudio_startPlayback
|
|
* psamp ... float array of length len with the audio data (mono)
|
|
* len ... number of float values in psamp
|
|
* volume ... 0.0f..2.0f will be multiplied with the output sample
|
|
*/
|
|
int kmaudio_playsamples(int id, float* psamp, int len, float volume);
|
|
|
|
/*
|
|
* reads len samples from device id into psamp
|
|
* returns: 0=ok, -1=error
|
|
* id ... device id returned by kmaudio_startCapture
|
|
* psamp ... float array of length len getting the audio data (mono)
|
|
* len ... number of float values to write into psamp
|
|
* volume ... 0.0f..2.0f will be multiplied with the input sample
|
|
* wait ... 1=wait for data, 0=return if not enough data available (in this case psamp will return 0,0,0...)
|
|
*/
|
|
int kmaudio_readsamples(int id, float* psamp, int len, float volume, int wait);
|
|
|
|
/*
|
|
* reads the names of detected sound devices
|
|
* *len...length of the returned string
|
|
* returns: pointer to device string
|
|
* Format of the device string:
|
|
* first byte = 3 ... ID of this string, followed by pure text:
|
|
* Active status of the following device "0" or "1"
|
|
* Name of playback devices, followed by ~
|
|
* separator ^
|
|
* Active status of the following device "0" or "1"
|
|
* Name of capture devices, followed by ~
|
|
* these names are used for calls to kmaudio_startCapture and kmaudio_startPlayback
|
|
* to select the device
|
|
*/
|
|
uint8_t* io_getAudioDevicelist(int* len);
|
|
|
|
/*
|
|
* returns the max level (within 1 second) of this stream in % (0..100)
|
|
* if the level >= 100 the signal will get clipped and distorted
|
|
*/
|
|
uint8_t kmaudio_maxlevel(int id);
|
|
|
|
/*
|
|
* closes a stream which was started by
|
|
* kmaudio_startCapture or kmaudio_startPlayback
|
|
* id ... stream ID which was returned by kmaudio_startCapture or kmaudio_startPlayback
|
|
*/
|
|
void close_stream(int id);
|
|
|
|
/*
|
|
* handle the FIFO which is used to buffer audio data
|
|
* pipenum ... stream ID which was returned by kmaudio_startCapture or kmaudio_startPlayback
|
|
* IMPORTANT: this information MUST be used to synchonize the data flow into
|
|
* the fifo. The speed is always defined by the audio sample rate
|
|
* by checking the fifo an application knows when it has to put more audio samples
|
|
* into the fifo
|
|
*/
|
|
// returns number of remaining elements (audio 16 bit short values)
|
|
int io_fifo_freespace(int pipenum);
|
|
|
|
// returns number of used elements (audio 16 bit short values)
|
|
int io_fifo_usedspace(int pipenum);
|
|
|
|
|
|
// clear the fifo
|
|
void io_fifo_clear(int pipenum);
|
|
|
|
// check if a playbackdevice is currently playing
|
|
int isPlaying(int id);
|
|
|
|
|
|
// -------- functions for internal use only --------
|
|
|
|
#define MAXDEVICES 200
|
|
#define MAXDEVNAMELENGTH 150
|
|
|
|
typedef struct _DEVLIST_ {
|
|
int index = 0; // index to this list
|
|
int active = 0; // 1=device valid, 0=possibly disconencted
|
|
char name[MAXDEVNAMELENGTH] = { 0 };// real name
|
|
int in_out = 0; // 0=capture device, 1=playback device, 2=both
|
|
int supports_44100 = 0; // 1 if supported
|
|
int supports_48000 = 0; // 1 if supported
|
|
int requested_samprate = 0; // sample rate requested by caller
|
|
int real_samprate = 0; // real sample rate of the device
|
|
int working = 0; // 0=not running, 1=initialized and working
|
|
int audio_playing = 0; // audio is currently playing, or not
|
|
#ifdef WIN32 // Windows using portaudio
|
|
int devnum = -1; // port audio device number
|
|
PaStreamParameters inputParameters;
|
|
PaStreamParameters outputParameters;
|
|
PaStream* capStream = NULL;
|
|
PaStream* pbStream = NULL;
|
|
#else // Linux using libsoundio
|
|
struct SoundIoDevice* io_pb_device = NULL;
|
|
struct SoundIoDevice* io_cap_device = NULL;
|
|
struct SoundIoInStream* instream = NULL;
|
|
struct SoundIoOutStream* outstream = NULL;
|
|
int stereo_mono = 2; // 1=mono, 2=stereo
|
|
char id[1000] = { 0 };
|
|
#endif
|
|
} DEVLIST;
|
|
|
|
int searchDevice(char* devname, int io);
|
|
void measure_speed_bps(int len);
|
|
void sleep_ms(int ms);
|
|
void io_write_fifo(int pipenum, float sample);
|
|
void io_write_fifo_short(int pipenum, int16_t sample);
|
|
void io_fifo_clear(int pipenum);
|
|
void init_pipes();
|
|
int io_read_fifo_num(int pipenum, float* data, int num);
|
|
int io_read_fifo(int pipenum, float* data);
|
|
int getRealSamprate(int idx);
|
|
int io_fifo_elems_avail(int pipenum);
|
|
void sleep_ms(int ms);
|
|
void io_buildAudioDevString();
|
|
void resampler_create(int devidx);
|
|
float* resample(int id, float* psamp, int len, int* pnewlen);
|
|
uint64_t getms();
|
|
void init_maxarray();
|
|
void kmaudio_detectDropouts(int id);
|
|
int io_read_fifo_num_short(int pipenum, int16_t* data, int num);
|
|
void close_capture_stream(int idx);
|
|
void close_playback_stream(int idx);
|
|
|
|
extern DEVLIST devlist[MAXDEVICES];
|
|
extern int devanz;
|
|
extern int keepcallbacksrunning;
|
|
|
|
#ifndef WIN32 // Linux
|
|
int kmaudio_init_linux();
|
|
void kmaudio_close_linux();
|
|
char* getDevID(char* devname, int io, int* pidx);
|
|
|
|
extern struct SoundIo* soundio;
|
|
#endif // ndef WIN32
|
|
|