mirror of
https://github.com/mpv-player/mpv
synced 2024-12-17 12:25:03 +00:00
ao_portaudio: remove this audio output
It's just completely useless. We have good native support for all 3 desktop platforms, and ao_sdl or ao_openal as fallbacks.
This commit is contained in:
parent
adeada149b
commit
4075518011
@ -184,19 +184,6 @@ Available audio output drivers are:
|
||||
disabled, it will use PulseAudio automatically updated timing
|
||||
information. Disabling this might help with e.g. networked audio.
|
||||
|
||||
``portaudio``
|
||||
PortAudio audio output driver. This works on all platforms, and has
|
||||
extensive MS Windows support.
|
||||
|
||||
.. note:: This driver is not very useful. It was added in the hope of
|
||||
providing portable audio API across all platforms, but turned
|
||||
out semi-broken and underfeatured.
|
||||
|
||||
``device``
|
||||
Specify the subdevice to use. Giving ``help`` as device name lists all
|
||||
devices found by PortAudio. Devices can be given as numeric values,
|
||||
starting from ``1``.
|
||||
|
||||
``dsound`` (Windows only)
|
||||
DirectX DirectSound audio output driver
|
||||
|
||||
|
@ -50,7 +50,6 @@ extern const struct ao_driver audio_out_dsound;
|
||||
extern const struct ao_driver audio_out_wasapi;
|
||||
extern const struct ao_driver audio_out_pcm;
|
||||
extern const struct ao_driver audio_out_lavc;
|
||||
extern const struct ao_driver audio_out_portaudio;
|
||||
extern const struct ao_driver audio_out_sdl;
|
||||
|
||||
static const struct ao_driver * const audio_out_drivers[] = {
|
||||
@ -72,9 +71,6 @@ static const struct ao_driver * const audio_out_drivers[] = {
|
||||
#endif
|
||||
#if HAVE_OSS_AUDIO
|
||||
&audio_out_oss,
|
||||
#endif
|
||||
#if HAVE_PORTAUDIO
|
||||
&audio_out_portaudio,
|
||||
#endif
|
||||
// wrappers:
|
||||
#if HAVE_JACK
|
||||
|
@ -1,276 +0,0 @@
|
||||
/*
|
||||
* This file is part of mplayer2.
|
||||
*
|
||||
* mplayer2 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.
|
||||
*
|
||||
* mplayer2 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 mplayer2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libavutil/common.h>
|
||||
#include <portaudio.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "options/m_option.h"
|
||||
#include "audio/format.h"
|
||||
#include "common/msg.h"
|
||||
#include "osdep/timer.h"
|
||||
#include "ao.h"
|
||||
#include "internal.h"
|
||||
|
||||
struct priv {
|
||||
PaStream *stream;
|
||||
|
||||
// Options
|
||||
char *cfg_device;
|
||||
};
|
||||
|
||||
struct format_map {
|
||||
int mp_format;
|
||||
PaSampleFormat pa_format;
|
||||
};
|
||||
|
||||
static const struct format_map format_maps[] = {
|
||||
// first entry is the default format
|
||||
{AF_FORMAT_S16, paInt16},
|
||||
{AF_FORMAT_S24, paInt24},
|
||||
{AF_FORMAT_S32, paInt32},
|
||||
{AF_FORMAT_S8, paInt8},
|
||||
{AF_FORMAT_U8, paUInt8},
|
||||
{AF_FORMAT_FLOAT, paFloat32},
|
||||
{AF_FORMAT_UNKNOWN, 0}
|
||||
};
|
||||
|
||||
static bool check_pa_ret(struct mp_log *log, int ret)
|
||||
{
|
||||
if (ret < 0) {
|
||||
mp_err(log, "%s\n", Pa_GetErrorText(ret));
|
||||
if (ret == paUnanticipatedHostError) {
|
||||
const PaHostErrorInfo* hosterr = Pa_GetLastHostErrorInfo();
|
||||
mp_err(log, "Host error: %s\n", hosterr->errorText);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define CHECK_PA_RET(ret) check_pa_ret(ao->log, (ret))
|
||||
|
||||
static int to_int(const char *s, int return_on_error)
|
||||
{
|
||||
char *endptr;
|
||||
int res = strtol(s, &endptr, 10);
|
||||
return (s[0] && !endptr[0]) ? res : return_on_error;
|
||||
}
|
||||
|
||||
static int find_device(struct mp_log *log, const char *name)
|
||||
{
|
||||
int found = paNoDevice;
|
||||
if (!name)
|
||||
return found;
|
||||
int help = strcmp(name, "help") == 0;
|
||||
int count = Pa_GetDeviceCount();
|
||||
check_pa_ret(log, count);
|
||||
int index = to_int(name, -1);
|
||||
if (help)
|
||||
mp_info(log, "PortAudio devices:\n");
|
||||
for (int n = 0; n < count; n++) {
|
||||
const PaDeviceInfo* info = Pa_GetDeviceInfo(n);
|
||||
if (help) {
|
||||
if (info->maxOutputChannels < 1)
|
||||
continue;
|
||||
mp_info(log, " %d '%s', %d channels, latency: %.2f "
|
||||
"ms, sample rate: %.0f\n", n, info->name,
|
||||
info->maxOutputChannels,
|
||||
info->defaultHighOutputLatency * 1000,
|
||||
info->defaultSampleRate);
|
||||
}
|
||||
if (strcmp(name, info->name) == 0 || n == index) {
|
||||
found = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == paNoDevice && !help)
|
||||
mp_warn(log, "Device '%s' not found!\n", name);
|
||||
return found;
|
||||
}
|
||||
|
||||
static int validate_device_opt(struct mp_log *log, const m_option_t *opt,
|
||||
struct bstr name, struct bstr param)
|
||||
{
|
||||
// Note: we do not check whether the device actually exist, because this
|
||||
// might break elaborate configs with several AOs trying several
|
||||
// devices. We do it merely for making "help" special.
|
||||
if (bstr_equals0(param, "help")) {
|
||||
if (!check_pa_ret(log, Pa_Initialize()))
|
||||
return M_OPT_EXIT;
|
||||
find_device(log, "help");
|
||||
Pa_Terminate();
|
||||
return M_OPT_EXIT - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void list_devs(struct ao *ao, struct ao_device_list *list)
|
||||
{
|
||||
if (Pa_Initialize() < 0)
|
||||
return;
|
||||
int count = Pa_GetDeviceCount(); // negative on error
|
||||
for (int n = 0; n < count; n++) {
|
||||
const PaDeviceInfo* info = Pa_GetDeviceInfo(n);
|
||||
char desc[1024];
|
||||
snprintf(desc, sizeof(desc), "%s, %d channels, latency: %.2f "
|
||||
"ms, sample rate: %.0f", info->name,
|
||||
info->maxOutputChannels,
|
||||
info->defaultHighOutputLatency * 1000,
|
||||
info->defaultSampleRate);
|
||||
ao_device_list_add(list, ao, &(struct ao_device_desc){info->name, desc});
|
||||
}
|
||||
Pa_Terminate();
|
||||
}
|
||||
|
||||
static int stream_callback(const void *input,
|
||||
void *output_v,
|
||||
unsigned long frameCount,
|
||||
const PaStreamCallbackTimeInfo *timeInfo,
|
||||
PaStreamCallbackFlags statusFlags,
|
||||
void *userData)
|
||||
{
|
||||
struct ao *ao = userData;
|
||||
|
||||
// NOTE: PA + ALSA in dmix mode seems to pretend that there is no latency
|
||||
// (outputBufferDacTime == currentTime)
|
||||
double play_time = timeInfo->outputBufferDacTime
|
||||
+ frameCount / (float)ao->samplerate;
|
||||
double latency = play_time - timeInfo->currentTime;
|
||||
int64_t end = mp_time_us() + MPMAX(0, latency * 1000000.0);
|
||||
|
||||
ao_read_data(ao, &output_v, frameCount, end);
|
||||
|
||||
return paContinue;
|
||||
}
|
||||
|
||||
static void uninit(struct ao *ao)
|
||||
{
|
||||
struct priv *priv = ao->priv;
|
||||
|
||||
if (priv->stream) {
|
||||
if (Pa_IsStreamActive(priv->stream) == 1)
|
||||
CHECK_PA_RET(Pa_StopStream(priv->stream));
|
||||
CHECK_PA_RET(Pa_CloseStream(priv->stream));
|
||||
}
|
||||
|
||||
Pa_Terminate();
|
||||
}
|
||||
|
||||
static int init(struct ao *ao)
|
||||
{
|
||||
struct priv *priv = ao->priv;
|
||||
|
||||
if (!CHECK_PA_RET(Pa_Initialize()))
|
||||
return -1;
|
||||
|
||||
int pa_device = Pa_GetDefaultOutputDevice();
|
||||
char *dev_name = priv->cfg_device;
|
||||
if (!dev_name || !dev_name[0])
|
||||
dev_name = ao->device;
|
||||
if (dev_name && dev_name[0])
|
||||
pa_device = find_device(ao->log, dev_name);
|
||||
if (pa_device == paNoDevice)
|
||||
goto error_exit;
|
||||
|
||||
// The actual channel order probably depends on the platform.
|
||||
struct mp_chmap_sel sel = {0};
|
||||
mp_chmap_sel_add_waveext_def(&sel);
|
||||
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
|
||||
goto error_exit;
|
||||
|
||||
PaStreamParameters sp = {
|
||||
.device = pa_device,
|
||||
.channelCount = ao->channels.num,
|
||||
.suggestedLatency
|
||||
= Pa_GetDeviceInfo(pa_device)->defaultHighOutputLatency,
|
||||
};
|
||||
|
||||
ao->format = af_fmt_from_planar(ao->format);
|
||||
|
||||
const struct format_map *fmt = format_maps;
|
||||
while (fmt->pa_format) {
|
||||
if (fmt->mp_format == ao->format) {
|
||||
PaStreamParameters test = sp;
|
||||
test.sampleFormat = fmt->pa_format;
|
||||
if (Pa_IsFormatSupported(NULL, &test, ao->samplerate) == paNoError)
|
||||
break;
|
||||
}
|
||||
fmt++;
|
||||
}
|
||||
if (!fmt->pa_format) {
|
||||
MP_VERBOSE(ao, "Unsupported format, using default.\n");
|
||||
fmt = format_maps;
|
||||
}
|
||||
|
||||
ao->format = fmt->mp_format;
|
||||
sp.sampleFormat = fmt->pa_format;
|
||||
int framelen = ao->channels.num * af_fmt2bps(ao->format);
|
||||
ao->bps = ao->samplerate * framelen;
|
||||
|
||||
if (!CHECK_PA_RET(Pa_IsFormatSupported(NULL, &sp, ao->samplerate)))
|
||||
goto error_exit;
|
||||
if (!CHECK_PA_RET(Pa_OpenStream(&priv->stream, NULL, &sp, ao->samplerate,
|
||||
paFramesPerBufferUnspecified, paNoFlag,
|
||||
stream_callback, ao)))
|
||||
goto error_exit;
|
||||
|
||||
return 0;
|
||||
|
||||
error_exit:
|
||||
uninit(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void reset(struct ao *ao)
|
||||
{
|
||||
struct priv *priv = ao->priv;
|
||||
|
||||
if (Pa_IsStreamStopped(priv->stream) != 1)
|
||||
CHECK_PA_RET(Pa_AbortStream(priv->stream));
|
||||
}
|
||||
|
||||
static void resume(struct ao *ao)
|
||||
{
|
||||
struct priv *priv = ao->priv;
|
||||
|
||||
if (Pa_IsStreamStopped(priv->stream) == 1)
|
||||
CHECK_PA_RET(Pa_StartStream(priv->stream));
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT struct priv
|
||||
|
||||
const struct ao_driver audio_out_portaudio = {
|
||||
.description = "PortAudio",
|
||||
.name = "portaudio",
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.reset = reset,
|
||||
.resume = resume,
|
||||
.list_devs = list_devs,
|
||||
.priv_size = sizeof(struct priv),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING_VALIDATE("device", cfg_device, 0, validate_device_opt),
|
||||
{0}
|
||||
},
|
||||
};
|
@ -204,7 +204,6 @@ options_state_machine() {
|
||||
opt_yes_no _rsound "RSound audio output"
|
||||
opt_yes_no _sndio "sndio audio output"
|
||||
opt_yes_no _pulse "Pulseaudio audio output"
|
||||
opt_yes_no _portaudio "PortAudio audio output"
|
||||
opt_yes_no _jack "JACK audio output"
|
||||
opt_yes_no _openal "OpenAL audio output"
|
||||
opt_yes_no _shm "X11/Xv shared memory"
|
||||
@ -704,8 +703,6 @@ check_statement_libs "sndio" $_sndio SNDIO sndio.h 'struct sio_par par; sio_init
|
||||
|
||||
check_pkg_config "PulseAudio" $_pulse PULSE 'libpulse >= 1.0'
|
||||
|
||||
check_pkg_config "PortAudio" $_portaudio PORTAUDIO 'portaudio-2.0 >= 19'
|
||||
|
||||
check_pkg_config "JACK" $_jack JACK 'jack'
|
||||
|
||||
check_pkg_config "OpenAL" $_openal OPENAL 'openal >= 1.13'
|
||||
|
@ -81,7 +81,6 @@ SOURCES-$(LIRC) += input/lirc.c
|
||||
SOURCES-$(OPENAL) += audio/out/ao_openal.c
|
||||
SOURCES-$(OSS_AUDIO) += audio/out/ao_oss.c
|
||||
SOURCES-$(PULSE) += audio/out/ao_pulse.c
|
||||
SOURCES-$(PORTAUDIO) += audio/out/ao_portaudio.c
|
||||
SOURCES-$(RSOUND) += audio/out/ao_rsound.c
|
||||
SOURCES-$(SNDIO) += audio/out/ao_sndio.c
|
||||
SOURCES-$(VDPAU) += video/vdpau.c video/vdpau_mixer.c \
|
||||
|
6
wscript
6
wscript
@ -515,12 +515,6 @@ audio_output_features = [
|
||||
'name': '--pulse',
|
||||
'desc': 'PulseAudio audio output',
|
||||
'func': check_pkg_config('libpulse', '>= 1.0')
|
||||
}, {
|
||||
'name': '--portaudio',
|
||||
'desc': 'PortAudio audio output',
|
||||
'deps': [ 'atomics' ],
|
||||
'func': check_pkg_config('portaudio-2.0', '>= 19'),
|
||||
'default': 'disable',
|
||||
}, {
|
||||
'name': '--jack',
|
||||
'desc': 'JACK audio output',
|
||||
|
@ -140,7 +140,6 @@ def build(ctx):
|
||||
( "audio/out/ao_openal.c", "openal" ),
|
||||
( "audio/out/ao_oss.c", "oss-audio" ),
|
||||
( "audio/out/ao_pcm.c" ),
|
||||
( "audio/out/ao_portaudio.c", "portaudio" ),
|
||||
( "audio/out/ao_pulse.c", "pulse" ),
|
||||
( "audio/out/ao_rsound.c", "rsound" ),
|
||||
( "audio/out/ao_sdl.c", "sdl1" ),
|
||||
|
Loading…
Reference in New Issue
Block a user