mirror of https://git.ffmpeg.org/ffmpeg.git
180 lines
3.8 KiB
C
180 lines
3.8 KiB
C
/*
|
|
* Linux audio play and grab interface
|
|
* Copyright (c) 2000, 2001 Gerard Lantau.
|
|
*
|
|
* This program 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.
|
|
*
|
|
* This program 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 this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <linux/soundcard.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <errno.h>
|
|
#include <sys/time.h>
|
|
|
|
#include "avformat.h"
|
|
|
|
const char *audio_device = "/dev/dsp";
|
|
|
|
typedef struct {
|
|
int fd;
|
|
int rate;
|
|
int channels;
|
|
} AudioData;
|
|
|
|
#define AUDIO_BLOCK_SIZE 4096
|
|
|
|
/* audio read support */
|
|
|
|
static int audio_read(URLContext *h, UINT8 *buf, int size)
|
|
{
|
|
AudioData *s = h->priv_data;
|
|
int ret;
|
|
|
|
ret = read(s->fd, buf, size);
|
|
if (ret < 0)
|
|
return -errno;
|
|
else
|
|
return ret;
|
|
}
|
|
|
|
static int audio_write(URLContext *h, UINT8 *buf, int size)
|
|
{
|
|
AudioData *s = h->priv_data;
|
|
int ret;
|
|
|
|
ret = write(s->fd, buf, size);
|
|
if (ret < 0)
|
|
return -errno;
|
|
else
|
|
return ret;
|
|
}
|
|
|
|
static int audio_get_format(URLContext *h, URLFormat *f)
|
|
{
|
|
AudioData *s = h->priv_data;
|
|
|
|
strcpy(f->format_name, "pcm");
|
|
f->sample_rate = s->rate;
|
|
f->channels = s->channels;
|
|
return 0;
|
|
}
|
|
|
|
/* URI syntax: 'audio:[rate[,channels]]'
|
|
default: rate=44100, channels=2
|
|
*/
|
|
static int audio_open(URLContext *h, const char *uri, int flags)
|
|
{
|
|
AudioData *s;
|
|
const char *p;
|
|
int freq, channels, audio_fd;
|
|
int tmp, err;
|
|
|
|
h->is_streamed = 1;
|
|
h->packet_size = AUDIO_BLOCK_SIZE;
|
|
|
|
s = malloc(sizeof(AudioData));
|
|
if (!s)
|
|
return -ENOMEM;
|
|
h->priv_data = s;
|
|
|
|
/* extract parameters */
|
|
p = uri;
|
|
strstart(p, "audio:", &p);
|
|
freq = strtol(p, (char **)&p, 0);
|
|
if (freq <= 0)
|
|
freq = 44100;
|
|
if (*p == ',')
|
|
p++;
|
|
channels = strtol(p, (char **)&p, 0);
|
|
if (channels <= 0)
|
|
channels = 2;
|
|
s->rate = freq;
|
|
s->channels = channels;
|
|
|
|
/* open linux audio device */
|
|
if (flags & URL_WRONLY)
|
|
audio_fd = open(audio_device,O_WRONLY);
|
|
else
|
|
audio_fd = open(audio_device,O_RDONLY);
|
|
if (audio_fd < 0) {
|
|
perror(audio_device);
|
|
return -EIO;
|
|
}
|
|
|
|
/* non blocking mode */
|
|
fcntl(audio_fd, F_SETFL, O_NONBLOCK);
|
|
|
|
#if 0
|
|
tmp=(NB_FRAGMENTS << 16) | FRAGMENT_BITS;
|
|
err=ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &tmp);
|
|
if (err < 0) {
|
|
perror("SNDCTL_DSP_SETFRAGMENT");
|
|
}
|
|
#endif
|
|
|
|
tmp=AFMT_S16_LE;
|
|
err=ioctl(audio_fd,SNDCTL_DSP_SETFMT,&tmp);
|
|
if (err < 0) {
|
|
perror("SNDCTL_DSP_SETFMT");
|
|
goto fail;
|
|
}
|
|
|
|
tmp= (channels == 2);
|
|
err=ioctl(audio_fd,SNDCTL_DSP_STEREO,&tmp);
|
|
if (err < 0) {
|
|
perror("SNDCTL_DSP_STEREO");
|
|
goto fail;
|
|
}
|
|
|
|
tmp = freq;
|
|
err=ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp);
|
|
if (err < 0) {
|
|
perror("SNDCTL_DSP_SPEED");
|
|
goto fail;
|
|
}
|
|
|
|
s->rate = tmp;
|
|
s->fd = audio_fd;
|
|
|
|
return 0;
|
|
fail:
|
|
close(audio_fd);
|
|
free(s);
|
|
return -EIO;
|
|
}
|
|
|
|
static int audio_close(URLContext *h)
|
|
{
|
|
AudioData *s = h->priv_data;
|
|
|
|
close(s->fd);
|
|
free(s);
|
|
return 0;
|
|
}
|
|
|
|
URLProtocol audio_protocol = {
|
|
"audio",
|
|
audio_open,
|
|
audio_read,
|
|
audio_write,
|
|
NULL, /* seek */
|
|
audio_close,
|
|
audio_get_format,
|
|
};
|