UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
portaudio_common.c
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2018-2023 CESNET, z. s. p. o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#include "config_unix.h"
41#include "config_win32.h"
42#endif
43
44#include <portaudio.h>
45#include <stdbool.h>
46
47#include "debug.h"
48#include "portaudio_common.h"
49#include "types.h"
50#include "utils/color_out.h"
51
52#define MOD_NAME "[PortAudio] "
53
54static const char *portaudio_get_api_name(PaDeviceIndex device) {
55 for (int i = 0; i < Pa_GetHostApiCount(); ++i) {
56 const PaHostApiInfo *info = Pa_GetHostApiInfo(i);
57 for (int j = 0; j < info->deviceCount; ++j) {
58 if (device == Pa_HostApiDeviceIndexToDeviceIndex(i, j)) {
59 return info->name;
60 }
61 }
62
63 }
64 return "(unknown API)";
65}
66
67const char *portaudio_get_device_name(PaDeviceIndex device) {
68 if( (device < 0) || (device >= Pa_GetDeviceCount()) )
69 {
70 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Requested info on non-existing device");
71 return NULL;
72 }
73
74 return Pa_GetDeviceInfo(device)->name;
75}
76
77static const char *portaudio_get_device_details(PaDeviceIndex device) {
78 assert(device >= 0 && device < Pa_GetDeviceCount());
79 const PaDeviceInfo *device_info = Pa_GetDeviceInfo(device);
80 _Thread_local static char buffer[1024];
81 snprintf(buffer, sizeof buffer, "(output channels: %d; input channels: %d; %s)", device_info->maxOutputChannels, device_info->maxInputChannels, portaudio_get_api_name(device));
82 return buffer;
83}
84
86{
87 int numDevices;
88 int i;
89
90 PaError error;
91
92 error = Pa_Initialize();
93 if(error != paNoError)
94 {
95 log_msg(LOG_LEVEL_ERROR, "error initializing portaudio\n");
96 log_msg(LOG_LEVEL_ERROR, "\tPortAudio error: %s\n", Pa_GetErrorText( error ) );
97 return;
98 }
99
100 numDevices = Pa_GetDeviceCount();
101 if( numDevices < 0)
102 {
103 log_msg(LOG_LEVEL_ERROR, "Error getting portaudio devices number\n");
104 goto error;
105 }
106 if( numDevices == 0)
107 {
108 log_msg(LOG_LEVEL_ERROR, "There are NO available audio devices!\n");
109 goto error;
110 }
111
112 color_printf("\t" TBOLD("portaudio") " - use default Portaudio device (marked with star)\n");
113
114 for(i = 0; i < numDevices; i++)
115 {
116 const char *highlight = TERM_BOLD;
117 const PaDeviceInfo *device_info = Pa_GetDeviceInfo(i);
118 // filter out (or differently highlight in verbose mode) unusable devices
119 if ((device_info->maxInputChannels == 0 && kind == PORTAUDIO_IN) ||
120 (device_info->maxOutputChannels == 0 && kind == PORTAUDIO_OUT)) {
122 continue;
123 } else {
125 }
126 }
127 if((i == Pa_GetDefaultInputDevice() && kind == PORTAUDIO_IN) ||
128 (i == Pa_GetDefaultOutputDevice() && kind == PORTAUDIO_OUT))
129 printf("(*) ");
130
131 color_printf("\t%sportaudio:%d" TERM_RESET " - %s%s" TERM_RESET " %s", highlight, i, highlight, portaudio_get_device_name(i), portaudio_get_device_details(i));
132 printf("\n");
133 }
134
135error:
136 Pa_Terminate();
137}
138
139void audio_portaudio_probe(struct device_info **available_devices, int *count, enum portaudio_device_direction dir)
140{
141 int numDevices = 0;
142 bool initialized = false;
143 const char *notice = ""; // we'll always include default device, but with a notice if something wrong
144
145 PaError error = Pa_Initialize();
146 if ( error != paNoError ) {
147 log_msg(LOG_LEVEL_ERROR, "\tPortAudio error: %s\n", Pa_GetErrorText(error));
148 notice = " (init error)";
149 } else {
150 initialized = true;
151 }
152
153 if (initialized && (numDevices = Pa_GetDeviceCount()) <= 0) {
154 notice = " (no device)";
155 numDevices = 0;
156 }
157 *available_devices = calloc(1 + numDevices, sizeof(struct device_info));
158 strncpy((*available_devices)[0].dev, "", sizeof (*available_devices)[0].dev);
159 snprintf((*available_devices)[0].name, sizeof (*available_devices)[0].name, "Portaudio default %s%s", dir == PORTAUDIO_IN ? "input" : "output", notice);
160 *count = 1;
161
162 for(int i = 0; i < numDevices; i++) {
163 const PaDeviceInfo *device_info = Pa_GetDeviceInfo(i);
164 if (((device_info->maxInputChannels == 0 && dir == PORTAUDIO_IN) ||
165 (device_info->maxOutputChannels == 0 && dir == PORTAUDIO_OUT))) {
166 continue;
167 }
168 snprintf((*available_devices)[*count].name, sizeof (*available_devices)[0].name, "%s", device_info->name);
169 snprintf((*available_devices)[*count].dev, sizeof (*available_devices)[0].dev, ":%d", i);
170 *count += 1;
171 }
172
173 if (initialized) {
174 Pa_Terminate();
175 }
176}
177
179 int error = Pa_Initialize();
180 if(error != paNoError) {
181 log_msg(LOG_LEVEL_INFO, MOD_NAME "Cannot get version.\n");
182 return;
183 }
184
185#ifdef HAVE_PA_GETVERSIONINFO
186 const PaVersionInfo *info = Pa_GetVersionInfo();
187
188 if (info && info->versionText) {
189 log_msg(LOG_LEVEL_INFO, MOD_NAME "Using %s\n", info->versionText);
190 }
191#else // compat
192 log_msg(LOG_LEVEL_INFO, MOD_NAME "Using %s\n", Pa_GetVersionText());
193#endif
194}
195
202 for (int i = 0; i < Pa_GetDeviceCount(); i++) {
203 const PaDeviceInfo *device_info = Pa_GetDeviceInfo(i);
204 if (strstr(device_info->name, name)) {
205 return i;
206 }
207 }
208 log_msg(LOG_LEVEL_ERROR, MOD_NAME "No device named \"%s\" was found!\n", name);
209 return -2;
210}
211
This file contains definition of some common audio types.
int color_printf(const char *format,...)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_FG_BRIGHT_BLACK
Definition color_out.h:55
#define TERM_RESET
Definition color_out.h:47
#define TBOLD(x)
Definition color_out.h:70
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
int count
Definition hd-rum.c:44
volatile int log_level
Definition debug.cpp:65
int portaudio_select_device_by_name(const char *name)
static const char * portaudio_get_device_details(PaDeviceIndex device)
void portaudio_print_version()
void audio_portaudio_probe(struct device_info **available_devices, int *count, enum portaudio_device_direction dir)
const char * portaudio_get_device_name(PaDeviceIndex device)
#define MOD_NAME
static const char * portaudio_get_api_name(PaDeviceIndex device)
void portaudio_print_help(enum portaudio_device_direction kind)
portaudio_device_direction
@ PORTAUDIO_OUT
@ PORTAUDIO_IN
const char * name
Definition settings.cpp:193
char name[1024]
human readable name of the device
Definition types.h:385