ao_alsa: use new option API (changes syntax)

This changes how device names are handled. Before this commit, device
names were mangled in strange ways to avoid clashing with the option
parser syntax. "." was replaced with ",", and "=" with ":" (the user had
to do the inverse to get the correct device name).

The "new" option parser has multiple ways to escape option strings, so
we don't need this confusing hack anymore.

Add an explicit note to the manpage as well.
This commit is contained in:
wm4 2013-07-21 21:51:51 +02:00
parent 38f81c618e
commit 2111d7bc05
2 changed files with 35 additions and 69 deletions

View File

@ -25,13 +25,20 @@ Available audio output drivers are:
``alsa`` (Linux only)
ALSA 0.9/1.x audio output driver
``noblock``
``no-block``
Sets noblock-mode.
``device=<device>``
Sets the device name. Replace any ',' with '.' and any ':' with '=' in
the ALSA device name. For hwac3 output via S/PDIF, use an "iec958" or
Sets the device name. For ac3 output via S/PDIF, use an "iec958" or
"spdif" device, unless you really know how to set it correctly.
.. note::
MPlayer and mplayer2 required you to replace any ',' with '.' and
any ':' with '=' in the ALSA device name. mpv does not do this anymore.
Instead, quote the device name:
``--ao=alsa:device=[plug:surround50]``
``oss``
OSS audio output driver

View File

@ -59,13 +59,14 @@ struct priv {
float delay_before_pause;
int buffersize;
int outburst;
int cfg_block;
char *cfg_device;
};
#define BUFFER_TIME 500000 // 0.5 s
#define FRAGCOUNT 16
#define ALSA_DEVICE_SIZE 256
#define CHECK_ALSA_ERROR(message) \
do { \
if (err < 0) { \
@ -253,37 +254,6 @@ alsa_error:
return CONTROL_ERROR;
}
static void parse_device(char *dest, const char *src, int len)
{
char *tmp;
memmove(dest, src, len);
dest[len] = 0;
while ((tmp = strrchr(dest, '.')))
tmp[0] = ',';
while ((tmp = strrchr(dest, '=')))
tmp[0] = ':';
}
static void print_help(void)
{
mp_tmsg(MSGT_AO, MSGL_FATAL,
"\n[AO_ALSA] -ao alsa commandline help:\n" \
"[AO_ALSA] Example: mpv -ao alsa:device=hw=0.3\n" \
"[AO_ALSA] Sets first card fourth hardware device.\n\n" \
"[AO_ALSA] Options:\n" \
"[AO_ALSA] noblock\n" \
"[AO_ALSA] Opens device in non-blocking mode.\n" \
"[AO_ALSA] device=<device-name>\n" \
"[AO_ALSA] Sets device (change , to . and : to =)\n");
}
static int str_maxlen(void *strp)
{
strarg_t *str = strp;
return str->len <= ALSA_DEVICE_SIZE;
}
static const int mp_to_alsa_format[][2] = {
{AF_FORMAT_S8, SND_PCM_FORMAT_S8},
{AF_FORMAT_U8, SND_PCM_FORMAT_U8},
@ -418,78 +388,58 @@ static int try_open_device(struct ao *ao, const char *device, int open_mode,
static int init(struct ao *ao, char *params)
{
int err;
int block;
strarg_t device;
snd_pcm_uframes_t chunk_size;
snd_pcm_uframes_t bufsize;
snd_pcm_uframes_t boundary;
const opt_t subopts[] = {
{"block", OPT_ARG_BOOL, &block, NULL},
{"device", OPT_ARG_STR, &device, str_maxlen},
{NULL}
};
struct priv *p = talloc_zero(ao, struct priv);
ao->priv = p;
char alsa_device[ALSA_DEVICE_SIZE + 1];
// make sure alsa_device is null-terminated even when using strncpy etc.
memset(alsa_device, 0, ALSA_DEVICE_SIZE + 1);
struct priv *p = ao->priv;
mp_msg(MSGT_AO, MSGL_V,
"alsa-init: requested format: %d Hz, %d channels, %x\n",
ao->samplerate, ao->channels.num, ao->format);
p->prepause_frames = 0;
p->delay_before_pause = 0;
//subdevice parsing
// set defaults
block = 1;
/* switch for spdif
* sets opening sequence for SPDIF
* sets also the playback and other switches 'on the fly'
* while opening the abstract alias for the spdif subdevice
* 'iec958'
*/
device.str = NULL;
const char *device;
if (AF_FORMAT_IS_IEC61937(ao->format)) {
device.str = "iec958";
device = "iec958";
mp_msg(MSGT_AO, MSGL_V,
"alsa-spdif-init: playing AC3/iec61937/iec958, %i channels\n",
ao->channels.num);
} else {
device.str = select_chmap(ao);
if (strcmp(device.str, "default") != 0 && ao->format == AF_FORMAT_FLOAT_NE)
device = select_chmap(ao);
if (strcmp(device, "default") != 0 && ao->format == AF_FORMAT_FLOAT_NE)
{
// hack - use the converter plugin (why the heck?)
device.str = talloc_asprintf(ao, "plug:%s", device.str);
device = talloc_asprintf(ao, "plug:%s", device);
}
}
device.len = strlen(device.str);
if (subopt_parse(params, subopts) != 0) {
print_help();
return 0;
}
parse_device(alsa_device, device.str, device.len);
if (p->cfg_device && p->cfg_device[0])
device = p->cfg_device;
mp_msg(MSGT_AO, MSGL_V, "alsa-init: using device %s\n", alsa_device);
mp_msg(MSGT_AO, MSGL_V, "alsa-init: using device %s\n", device);
p->can_pause = 1;
mp_msg(MSGT_AO, MSGL_V, "alsa-init: using ALSA %s\n", snd_asoundlib_version());
snd_lib_error_set_handler(alsa_error_handler);
int open_mode = block ? 0 : SND_PCM_NONBLOCK;
int open_mode = p->cfg_block ? 0 : SND_PCM_NONBLOCK;
int isac3 = AF_FORMAT_IS_IEC61937(ao->format);
//modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
err = try_open_device(ao, alsa_device, open_mode, isac3);
err = try_open_device(ao, device, open_mode, isac3);
if (err < 0) {
if (err != -EBUSY && !block) {
if (err != -EBUSY && !p->cfg_block) {
mp_tmsg(MSGT_AO, MSGL_INFO, "[AO_ALSA] Open in nonblock-mode "
"failed, trying to open in block-mode.\n");
err = try_open_device(ao, alsa_device, 0, isac3);
err = try_open_device(ao, device, 0, isac3);
}
CHECK_ALSA_ERROR("Playback open error");
}
@ -822,6 +772,8 @@ static float get_delay(struct ao *ao)
return 0;
}
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_alsa = {
.info = &(const struct ao_info) {
"ALSA-0.9.x-1.x audio output",
@ -838,4 +790,11 @@ const struct ao_driver audio_out_alsa = {
.pause = audio_pause,
.resume = audio_resume,
.reset = reset,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) { .cfg_block = 1 },
.options = (const struct m_option[]) {
OPT_STRING("device", cfg_device, 0),
OPT_FLAG("block", cfg_block, 0),
{0}
},
};