oss.c 3.74 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1 2
/*
 * Linux audio play and grab interface
3
 * Copyright (c) 2000, 2001 Fabrice Bellard
Fabrice Bellard's avatar
Fabrice Bellard committed
4
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
11
 *
12
 * Libav is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with Libav; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Fabrice Bellard's avatar
Fabrice Bellard committed
20
 */
Fabrice Bellard's avatar
Fabrice Bellard committed
21

22
#include "config.h"
23

Fabrice Bellard's avatar
Fabrice Bellard committed
24
#include <string.h>
25

26
#if HAVE_SOUNDCARD_H
27 28
#include <soundcard.h>
#else
29
#include <sys/soundcard.h>
30
#endif
31

Fabrice Bellard's avatar
Fabrice Bellard committed
32 33 34 35
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>

36
#include "libavutil/log.h"
37

38
#include "libavcodec/avcodec.h"
39

40
#include "libavformat/avformat.h"
41

42
#include "oss.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
43

44 45
int ff_oss_audio_open(AVFormatContext *s1, int is_output,
                      const char *audio_device)
Fabrice Bellard's avatar
Fabrice Bellard committed
46
{
47
    OSSAudioData *s = s1->priv_data;
48
    int audio_fd;
Fabrice Bellard's avatar
Fabrice Bellard committed
49
    int tmp, err;
50
    char *flip = getenv("AUDIO_FLIP_LEFT");
51
    char errbuff[128];
Fabrice Bellard's avatar
Fabrice Bellard committed
52

53
    if (is_output)
54
        audio_fd = avpriv_open(audio_device, O_WRONLY);
Fabrice Bellard's avatar
Fabrice Bellard committed
55
    else
56
        audio_fd = avpriv_open(audio_device, O_RDONLY);
Fabrice Bellard's avatar
Fabrice Bellard committed
57
    if (audio_fd < 0) {
58
        av_log(s1, AV_LOG_ERROR, "%s: %s\n", audio_device, strerror(errno));
59
        return AVERROR(EIO);
Fabrice Bellard's avatar
Fabrice Bellard committed
60 61
    }

62 63 64 65
    if (flip && *flip == '1') {
        s->flip_left = 1;
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
66
    /* non blocking mode */
67 68
    if (!is_output)
        fcntl(audio_fd, F_SETFL, O_NONBLOCK);
Fabrice Bellard's avatar
Fabrice Bellard committed
69

70
    s->frame_size = OSS_AUDIO_BLOCK_SIZE;
Fabrice Bellard's avatar
Fabrice Bellard committed
71

72 73 74 75 76 77 78 79 80 81 82 83
#define CHECK_IOCTL_ERROR(event)                                              \
    if (err < 0) {                                                            \
        av_strerror(AVERROR(errno), errbuff, sizeof(errbuff));                \
        av_log(s1, AV_LOG_ERROR, #event ": %s\n", errbuff);                   \
        goto fail;                                                            \
    }

    /* select format : favour native format
     * We don't CHECK_IOCTL_ERROR here because even if failed OSS still may be
     * usable. If OSS is not usable the SNDCTL_DSP_SETFMTS later is going to
     * fail anyway. */
    (void) ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &tmp);
84

85
#if HAVE_BIGENDIAN
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
    if (tmp & AFMT_S16_BE) {
        tmp = AFMT_S16_BE;
    } else if (tmp & AFMT_S16_LE) {
        tmp = AFMT_S16_LE;
    } else {
        tmp = 0;
    }
#else
    if (tmp & AFMT_S16_LE) {
        tmp = AFMT_S16_LE;
    } else if (tmp & AFMT_S16_BE) {
        tmp = AFMT_S16_BE;
    } else {
        tmp = 0;
    }
#endif

    switch(tmp) {
    case AFMT_S16_LE:
105
        s->codec_id = AV_CODEC_ID_PCM_S16LE;
106 107
        break;
    case AFMT_S16_BE:
108
        s->codec_id = AV_CODEC_ID_PCM_S16BE;
109 110
        break;
    default:
111
        av_log(s1, AV_LOG_ERROR, "Soundcard does not support 16 bit sample format\n");
112
        close(audio_fd);
113
        return AVERROR(EIO);
114 115
    }
    err=ioctl(audio_fd, SNDCTL_DSP_SETFMT, &tmp);
116
    CHECK_IOCTL_ERROR(SNDCTL_DSP_SETFMTS)
117

118 119
    tmp = (s->channels == 2);
    err = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
120
    CHECK_IOCTL_ERROR(SNDCTL_DSP_STEREO)
121

122 123
    tmp = s->sample_rate;
    err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp);
124
    CHECK_IOCTL_ERROR(SNDCTL_DSP_SPEED)
125
    s->sample_rate = tmp; /* store real sample rate */
Fabrice Bellard's avatar
Fabrice Bellard committed
126 127 128 129 130
    s->fd = audio_fd;

    return 0;
 fail:
    close(audio_fd);
131
    return AVERROR(EIO);
132
#undef CHECK_IOCTL_ERROR
Fabrice Bellard's avatar
Fabrice Bellard committed
133 134
}

135
int ff_oss_audio_close(OSSAudioData *s)
Fabrice Bellard's avatar
Fabrice Bellard committed
136 137
{
    close(s->fd);
138 139
    return 0;
}