2010-01-30 22:26:47 +00:00
|
|
|
/*
|
|
|
|
* This file is part of MPlayer.
|
|
|
|
*
|
|
|
|
* MPlayer 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.
|
|
|
|
*
|
|
|
|
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
|
2002-08-31 22:41:29 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2002-09-22 02:33:28 +00:00
|
|
|
#include <unistd.h>
|
2002-08-31 22:41:29 +00:00
|
|
|
|
2002-08-21 22:50:40 +00:00
|
|
|
#include "config.h"
|
2002-08-31 22:41:29 +00:00
|
|
|
|
2002-08-21 22:50:40 +00:00
|
|
|
#include "audio_in.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/msg.h"
|
2002-08-21 22:50:40 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
// sanitizes ai structure before calling other functions
|
2013-12-21 19:24:20 +00:00
|
|
|
int audio_in_init(audio_in_t *ai, struct mp_log *log, int type)
|
2002-08-21 22:50:40 +00:00
|
|
|
{
|
|
|
|
ai->type = type;
|
|
|
|
ai->setup = 0;
|
2013-12-21 19:24:20 +00:00
|
|
|
ai->log = log;
|
2002-08-21 22:50:40 +00:00
|
|
|
|
|
|
|
ai->channels = -1;
|
|
|
|
ai->samplerate = -1;
|
|
|
|
ai->blocksize = -1;
|
|
|
|
ai->bytes_per_sample = -1;
|
|
|
|
ai->samplesize = -1;
|
|
|
|
|
|
|
|
switch (ai->type) {
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_ALSA
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_ALSA:
|
|
|
|
ai->alsa.handle = NULL;
|
|
|
|
ai->alsa.log = NULL;
|
|
|
|
ai->alsa.device = strdup("default");
|
|
|
|
return 0;
|
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_OSS_AUDIO
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_OSS:
|
|
|
|
ai->oss.audio_fd = -1;
|
|
|
|
ai->oss.device = strdup("/dev/dsp");
|
|
|
|
return 0;
|
2013-09-28 16:01:12 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_SNDIO
|
2013-09-28 16:01:12 +00:00
|
|
|
case AUDIO_IN_SNDIO:
|
|
|
|
ai->sndio.hdl = NULL;
|
|
|
|
ai->sndio.device = strdup("default");
|
|
|
|
return 0;
|
2002-10-22 15:14:30 +00:00
|
|
|
#endif
|
2002-08-21 22:50:40 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int audio_in_setup(audio_in_t *ai)
|
|
|
|
{
|
2009-07-06 23:26:13 +00:00
|
|
|
|
2002-08-21 22:50:40 +00:00
|
|
|
switch (ai->type) {
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_ALSA
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_ALSA:
|
|
|
|
if (ai_alsa_init(ai) < 0) return -1;
|
|
|
|
ai->setup = 1;
|
|
|
|
return 0;
|
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_OSS_AUDIO
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_OSS:
|
|
|
|
if (ai_oss_init(ai) < 0) return -1;
|
|
|
|
ai->setup = 1;
|
|
|
|
return 0;
|
2013-09-28 16:01:12 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_SNDIO
|
2013-09-28 16:01:12 +00:00
|
|
|
case AUDIO_IN_SNDIO:
|
|
|
|
if (ai_sndio_init(ai) < 0) return -1;
|
|
|
|
ai->setup = 1;
|
|
|
|
return 0;
|
2002-10-22 15:14:30 +00:00
|
|
|
#endif
|
2002-08-21 22:50:40 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int audio_in_set_samplerate(audio_in_t *ai, int rate)
|
|
|
|
{
|
|
|
|
switch (ai->type) {
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_ALSA
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_ALSA:
|
|
|
|
ai->req_samplerate = rate;
|
|
|
|
if (!ai->setup) return 0;
|
|
|
|
if (ai_alsa_setup(ai) < 0) return -1;
|
|
|
|
return ai->samplerate;
|
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_OSS_AUDIO
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_OSS:
|
|
|
|
ai->req_samplerate = rate;
|
|
|
|
if (!ai->setup) return 0;
|
|
|
|
if (ai_oss_set_samplerate(ai) < 0) return -1;
|
|
|
|
return ai->samplerate;
|
2013-09-28 16:01:12 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_SNDIO
|
2013-09-28 16:01:12 +00:00
|
|
|
case AUDIO_IN_SNDIO:
|
|
|
|
ai->req_samplerate = rate;
|
|
|
|
if (!ai->setup) return 0;
|
|
|
|
if (ai_sndio_setup(ai) < 0) return -1;
|
|
|
|
return ai->samplerate;
|
2002-10-22 15:14:30 +00:00
|
|
|
#endif
|
2002-08-21 22:50:40 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int audio_in_set_channels(audio_in_t *ai, int channels)
|
|
|
|
{
|
|
|
|
switch (ai->type) {
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_ALSA
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_ALSA:
|
|
|
|
ai->req_channels = channels;
|
|
|
|
if (!ai->setup) return 0;
|
|
|
|
if (ai_alsa_setup(ai) < 0) return -1;
|
|
|
|
return ai->channels;
|
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_OSS_AUDIO
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_OSS:
|
|
|
|
ai->req_channels = channels;
|
|
|
|
if (!ai->setup) return 0;
|
|
|
|
if (ai_oss_set_channels(ai) < 0) return -1;
|
|
|
|
return ai->channels;
|
2013-09-28 16:01:12 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_SNDIO
|
2013-09-28 16:01:12 +00:00
|
|
|
case AUDIO_IN_SNDIO:
|
|
|
|
ai->req_channels = channels;
|
|
|
|
if (!ai->setup) return 0;
|
|
|
|
if (ai_sndio_setup(ai) < 0) return -1;
|
|
|
|
return ai->channels;
|
2002-10-22 15:14:30 +00:00
|
|
|
#endif
|
2002-08-21 22:50:40 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int audio_in_set_device(audio_in_t *ai, char *device)
|
|
|
|
{
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_ALSA
|
2002-08-21 22:50:40 +00:00
|
|
|
int i;
|
2002-11-23 10:58:14 +00:00
|
|
|
#endif
|
2002-08-21 22:50:40 +00:00
|
|
|
if (ai->setup) return -1;
|
|
|
|
switch (ai->type) {
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_ALSA
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_ALSA:
|
2010-11-07 12:47:40 +00:00
|
|
|
free(ai->alsa.device);
|
2002-08-21 22:50:40 +00:00
|
|
|
ai->alsa.device = strdup(device);
|
|
|
|
/* mplayer cannot handle colons in arguments */
|
2002-10-02 16:56:54 +00:00
|
|
|
for (i = 0; i < (int)strlen(ai->alsa.device); i++) {
|
2002-08-22 23:05:58 +00:00
|
|
|
if (ai->alsa.device[i] == '.') ai->alsa.device[i] = ':';
|
2002-08-21 22:50:40 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_OSS_AUDIO
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_OSS:
|
2010-11-07 12:47:40 +00:00
|
|
|
free(ai->oss.device);
|
2002-08-21 22:50:40 +00:00
|
|
|
ai->oss.device = strdup(device);
|
|
|
|
return 0;
|
2013-09-28 16:01:12 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_SNDIO
|
2013-09-28 16:01:12 +00:00
|
|
|
case AUDIO_IN_SNDIO:
|
|
|
|
if (ai->sndio.device) free(ai->sndio.device);
|
|
|
|
ai->sndio.device = strdup(device);
|
|
|
|
return 0;
|
2002-10-22 15:14:30 +00:00
|
|
|
#endif
|
2002-08-21 22:50:40 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int audio_in_uninit(audio_in_t *ai)
|
|
|
|
{
|
|
|
|
if (ai->setup) {
|
|
|
|
switch (ai->type) {
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_ALSA
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_ALSA:
|
|
|
|
if (ai->alsa.log)
|
|
|
|
snd_output_close(ai->alsa.log);
|
|
|
|
if (ai->alsa.handle) {
|
|
|
|
snd_pcm_close(ai->alsa.handle);
|
|
|
|
}
|
|
|
|
ai->setup = 0;
|
|
|
|
return 0;
|
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_OSS_AUDIO
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_OSS:
|
|
|
|
close(ai->oss.audio_fd);
|
|
|
|
ai->setup = 0;
|
|
|
|
return 0;
|
2013-09-28 16:01:12 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_SNDIO
|
2013-09-28 16:01:12 +00:00
|
|
|
case AUDIO_IN_SNDIO:
|
|
|
|
if (ai->sndio.hdl)
|
|
|
|
sio_close(ai->sndio.hdl);
|
|
|
|
ai->setup = 0;
|
|
|
|
return 0;
|
2002-10-22 15:14:30 +00:00
|
|
|
#endif
|
2002-08-21 22:50:40 +00:00
|
|
|
}
|
|
|
|
}
|
2002-09-22 02:33:28 +00:00
|
|
|
return -1;
|
2002-08-21 22:50:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int audio_in_start_capture(audio_in_t *ai)
|
|
|
|
{
|
|
|
|
switch (ai->type) {
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_ALSA
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_ALSA:
|
|
|
|
return snd_pcm_start(ai->alsa.handle);
|
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_OSS_AUDIO
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_OSS:
|
|
|
|
return 0;
|
2013-09-28 16:01:12 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_SNDIO
|
2013-09-28 16:01:12 +00:00
|
|
|
case AUDIO_IN_SNDIO:
|
|
|
|
if (!sio_start(ai->sndio.hdl))
|
|
|
|
return -1;
|
|
|
|
return 0;
|
2002-10-22 15:14:30 +00:00
|
|
|
#endif
|
2002-08-21 22:50:40 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int audio_in_read_chunk(audio_in_t *ai, unsigned char *buffer)
|
|
|
|
{
|
|
|
|
int ret;
|
2009-07-06 23:26:13 +00:00
|
|
|
|
2002-08-21 22:50:40 +00:00
|
|
|
switch (ai->type) {
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_ALSA
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_ALSA:
|
|
|
|
ret = snd_pcm_readi(ai->alsa.handle, buffer, ai->alsa.chunk_size);
|
|
|
|
if (ret != ai->alsa.chunk_size) {
|
|
|
|
if (ret < 0) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(ai, "\nError reading audio: %s\n", snd_strerror(ret));
|
2002-10-02 16:56:54 +00:00
|
|
|
if (ret == -EPIPE) {
|
|
|
|
if (ai_alsa_xrun(ai) == 0) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(ai, "Recovered from cross-run, some frames may be left out!\n");
|
2002-10-02 16:56:54 +00:00
|
|
|
} else {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(ai, "Fatal error, cannot recover!\n");
|
2002-10-02 16:56:54 +00:00
|
|
|
}
|
|
|
|
}
|
2002-08-21 22:50:40 +00:00
|
|
|
} else {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(ai, "\nNot enough audio samples!\n");
|
2002-08-21 22:50:40 +00:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_OSS_AUDIO
|
2002-08-21 22:50:40 +00:00
|
|
|
case AUDIO_IN_OSS:
|
|
|
|
ret = read(ai->oss.audio_fd, buffer, ai->blocksize);
|
2013-09-28 16:01:12 +00:00
|
|
|
if (ret != ai->blocksize) {
|
|
|
|
if (ret < 0) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(ai, "\nError reading audio: %s\n", strerror(errno));
|
2013-09-28 16:01:12 +00:00
|
|
|
|
|
|
|
} else {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(ai, "\nNot enough audio samples!\n");
|
2013-09-28 16:01:12 +00:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_SNDIO
|
2013-09-28 16:01:12 +00:00
|
|
|
case AUDIO_IN_SNDIO:
|
|
|
|
ret = sio_read(ai->sndio.hdl, buffer, ai->blocksize);
|
2002-08-21 22:50:40 +00:00
|
|
|
if (ret != ai->blocksize) {
|
|
|
|
if (ret < 0) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(ai, "\nError reading audio: %s\n", strerror(errno));
|
2002-08-21 22:50:40 +00:00
|
|
|
} else {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(ai, "\nNot enough audio samples!\n");
|
2002-08-21 22:50:40 +00:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return ret;
|
2002-10-22 15:14:30 +00:00
|
|
|
#endif
|
2002-08-21 22:50:40 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|