diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/out/ao_oss.c | 212 |
1 files changed, 108 insertions, 104 deletions
diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c index a2d2243ebd..3f7a6edb47 100644 --- a/audio/out/ao_oss.c +++ b/audio/out/ao_oss.c @@ -233,8 +233,7 @@ static int device_writable(struct ao *ao) return poll(&fd, 1, 0); } -// close audio device -static void uninit(struct ao *ao) +static void close_device(struct ao *ao) { struct priv *p = ao->priv; if (p->audio_fd == -1) @@ -246,51 +245,20 @@ static void uninit(struct ao *ao) p->audio_fd = -1; } -// open & setup audio device -// return: 0=success -1=fail -static int init(struct ao *ao) +// close audio device +static void uninit(struct ao *ao) +{ + close_device(ao); +} + +static int reopen_device(struct ao *ao, bool allow_format_changes) { struct priv *p = ao->priv; int oss_format; - const char *mchan = NULL; - if (p->cfg_oss_mixer_channel && p->cfg_oss_mixer_channel[0]) - mchan = p->cfg_oss_mixer_channel; - - if (mchan) { - int fd, devs, i; - - if ((fd = open(p->oss_mixer_device, O_RDONLY)) == -1) { - MP_ERR(ao, "Can't open mixer device %s: %s\n", - p->oss_mixer_device, strerror(errno)); - } else { - ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devs); - close(fd); - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if (!strcasecmp(mixer_channels[i], mchan)) { - if (!(devs & (1 << i))) { - MP_ERR(ao, "Audio card mixer does not have " - "channel '%s', using default.\n", mchan); - i = SOUND_MIXER_NRDEVICES + 1; - break; - } - p->oss_mixer_channel = i; - break; - } - } - if (i == SOUND_MIXER_NRDEVICES) { - MP_ERR(ao, "Audio card mixer does not have " - "channel '%s', using default.\n", mchan); - } - } - } else { - p->oss_mixer_channel = SOUND_MIXER_PCM; - } - - MP_VERBOSE(ao, "using '%s' dsp device\n", p->dsp); - MP_VERBOSE(ao, "using '%s' mixer device\n", p->oss_mixer_device); - MP_VERBOSE(ao, "using '%s' mixer device\n", mixer_channels[p->oss_mixer_channel]); + int samplerate = ao->samplerate; + int format = ao->format; + struct mp_chmap channels = ao->channels; #ifdef __linux__ p->audio_fd = open(p->dsp, O_WRONLY | O_NONBLOCK); @@ -314,67 +282,65 @@ static int init(struct ao *ao) fcntl(p->audio_fd, F_SETFD, FD_CLOEXEC); #endif - ao->format = af_fmt_from_planar(ao->format); - - if (AF_FORMAT_IS_AC3(ao->format)) { - ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate); + if (AF_FORMAT_IS_AC3(format)) { + ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &samplerate); } ac3_retry: - if (AF_FORMAT_IS_AC3(ao->format)) - ao->format = AF_FORMAT_AC3; - oss_format = format2oss(ao->format); + if (AF_FORMAT_IS_AC3(format)) + format = AF_FORMAT_AC3; + oss_format = format2oss(format); if (oss_format == -1) { MP_VERBOSE(ao, "Unknown/not supported internal format: %s\n", - af_fmt_to_str(ao->format)); + af_fmt_to_str(format)); #if defined(AFMT_S32_LE) && defined(AFMT_S32_BE) #if BYTE_ORDER == BIG_ENDIAN oss_format = AFMT_S32_BE; #else oss_format = AFMT_S32_LE; #endif - ao->format = AF_FORMAT_S32; + format = AF_FORMAT_S32; #elif defined(AFMT_S24_LE) && defined(AFMT_S24_BE) #if BYTE_ORDER == BIG_ENDIAN oss_format = AFMT_S24_BE; #else oss_format = AFMT_S24_LE; #endif - ao->format = AF_FORMAT_S24; + format = AF_FORMAT_S24; #else #if BYTE_ORDER == BIG_ENDIAN oss_format = AFMT_S16_BE; #else oss_format = AFMT_S16_LE; #endif - ao->format = AF_FORMAT_S16; + format = AF_FORMAT_S16; #endif } if (ioctl(p->audio_fd, SNDCTL_DSP_SETFMT, &oss_format) < 0 || - oss_format != format2oss(ao->format)) + oss_format != format2oss(format)) { MP_WARN(ao, "Can't set audio device %s to %s output, trying %s...\n", - p->dsp, af_fmt_to_str(ao->format), + p->dsp, af_fmt_to_str(format), af_fmt_to_str(AF_FORMAT_S16)); - ao->format = AF_FORMAT_S16; + format = AF_FORMAT_S16; goto ac3_retry; } - ao->format = oss2format(oss_format); - if (ao->format == -1) { + format = oss2format(oss_format); + if (format == -1) { MP_ERR(ao, "Unknown/Unsupported OSS format: %x.\n", oss_format); goto fail; } - MP_VERBOSE(ao, "sample format: %s\n", af_fmt_to_str(ao->format)); + MP_VERBOSE(ao, "sample format: %s\n", af_fmt_to_str(format)); - if (!AF_FORMAT_IS_AC3(ao->format)) { + if (!AF_FORMAT_IS_AC3(format)) { struct mp_chmap_sel sel = {0}; for (int n = 0; n < MP_NUM_CHANNELS + 1; n++) mp_chmap_sel_add_map(&sel, &oss_layouts[n]); - if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) + if (!ao_chmap_sel_adjust(ao, &sel, &channels)) goto fail; - int reqchannels = ao->channels.num; + int reqchannels = channels.num; // We only use SNDCTL_DSP_CHANNELS for >2 channels, in case some drivers don't have it if (reqchannels > 2) { int nchannels = reqchannels; @@ -392,14 +358,14 @@ ac3_retry: reqchannels); goto fail; } - if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, c + 1)) + if (!ao_chmap_sel_get_def(ao, &sel, &channels, c + 1)) goto fail; } MP_VERBOSE(ao, "using %d channels (requested: %d)\n", - ao->channels.num, reqchannels); + channels.num, reqchannels); // set rate - ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate); - MP_VERBOSE(ao, "using %d Hz samplerate\n", ao->samplerate); + ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &samplerate); + MP_VERBOSE(ao, "using %d Hz samplerate\n", samplerate); } if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &p->zz) == -1) { @@ -418,6 +384,78 @@ ac3_retry: p->outburst = p->zz.fragsize; } + if (allow_format_changes) { + ao->format = format; + ao->samplerate = samplerate; + ao->channels = channels; + } else { + if (format != ao->format || samplerate != ao->samplerate || + !mp_chmap_equals(&channels, &ao->channels)) + { + MP_ERR(ao, "Could not reselect previous audio format.\n"); + goto fail; + } + } + + p->outburst -= p->outburst % (channels.num * af_fmt2bps(format)); // round down + + return 0; + +fail: + close_device(ao); + return -1; +} + +// open & setup audio device +// return: 0=success -1=fail +static int init(struct ao *ao) +{ + struct priv *p = ao->priv; + + const char *mchan = NULL; + if (p->cfg_oss_mixer_channel && p->cfg_oss_mixer_channel[0]) + mchan = p->cfg_oss_mixer_channel; + + if (mchan) { + int fd, devs, i; + + if ((fd = open(p->oss_mixer_device, O_RDONLY)) == -1) { + MP_ERR(ao, "Can't open mixer device %s: %s\n", + p->oss_mixer_device, strerror(errno)); + } else { + ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devs); + close(fd); + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (!strcasecmp(mixer_channels[i], mchan)) { + if (!(devs & (1 << i))) { + MP_ERR(ao, "Audio card mixer does not have " + "channel '%s', using default.\n", mchan); + i = SOUND_MIXER_NRDEVICES + 1; + break; + } + p->oss_mixer_channel = i; + break; + } + } + if (i == SOUND_MIXER_NRDEVICES) { + MP_ERR(ao, "Audio card mixer does not have " + "channel '%s', using default.\n", mchan); + } + } + } else { + p->oss_mixer_channel = SOUND_MIXER_PCM; + } + + MP_VERBOSE(ao, "using '%s' dsp device\n", p->dsp); + MP_VERBOSE(ao, "using '%s' mixer device\n", p->oss_mixer_device); + MP_VERBOSE(ao, "using '%s' mixer device\n", mixer_channels[p->oss_mixer_channel]); + + ao->format = af_fmt_from_planar(ao->format); + + if (reopen_device(ao, true) < 0) + goto fail; + if (p->buffersize == -1) { // Measuring buffer size: void *data = malloc(p->outburst); @@ -438,10 +476,6 @@ ac3_retry: } } - ao->bps = ao->channels.num * af_fmt2bps(ao->format); - p->outburst -= p->outburst % ao->bps; // round down - ao->bps *= ao->samplerate; - return 0; fail: @@ -459,48 +493,18 @@ static void drain(struct ao *ao) #endif } -#if !KEEP_DEVICE -static void close_device(struct ao *ao) -{ - struct priv *p = ao->priv; - close(p->audio_fd); - p->audio_fd = -1; -} -#endif - // stop playing and empty buffers (for seeking/pause) static void reset(struct ao *ao) { - struct priv *p = ao->priv; #if KEEP_DEVICE + struct priv *p = ao->priv; ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL); #else close_device(ao); - p->audio_fd = open(p->dsp, O_WRONLY); - if (p->audio_fd < 0) { - MP_ERR(ao, "Fatal error: *** CANNOT " - "RE-OPEN / RESET AUDIO DEVICE *** %s\n", strerror(errno)); + if (reopen_device(ao, false) < 0) { + MP_ERR(ao, "Fatal error: *** CANNOT RE-OPEN / RESET AUDIO DEVICE ***\n"); return; } - -#if defined(FD_CLOEXEC) && defined(F_SETFD) - fcntl(p->audio_fd, F_SETFD, FD_CLOEXEC); -#endif - - int oss_format = format2oss(ao->format); - if (AF_FORMAT_IS_AC3(ao->format)) - ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate); - ioctl(p->audio_fd, SNDCTL_DSP_SETFMT, &oss_format); - if (!AF_FORMAT_IS_AC3(ao->format)) { - int c = ao->channels.num; - if (ao->channels.num > 2) - ioctl(p->audio_fd, SNDCTL_DSP_CHANNELS, &c); - else { - c--; - ioctl(p->audio_fd, SNDCTL_DSP_STEREO, &c); - } - ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate); - } #endif } |