1
2
3 /*
4 * Author: Arvin Schnell
5 */
6
7
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <fcntl.h>
12 #include <sys/ioctl.h>
13 #ifdef __NetBSD__
14 # include <soundcard.h>
15 #else
16 # include <sys/soundcard.h>
17 #endif
18 #include <math.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <iostream>
22
23 using std::cerr;
24
25 #include "pcm-oss.h"
26
27
PCMOSS(const char * name,pcm_type_t type,pcm_mode_t mode,pcm_format_t format,int channels,int rate,int buffer_size)28 PCMOSS::PCMOSS (const char* name, pcm_type_t type, pcm_mode_t mode,
29 pcm_format_t format, int channels, int rate, int buffer_size)
30 : PCM (name, type, mode, format, channels, rate, buffer_size),
31 fd (-1)
32 {
33 if (channels != 1 && channels != 2) {
34 cerr << "error: Illegal number of channels\n";
35 return;
36 }
37
38 if (format != S8 && format != S16) {
39 cerr << "error: Illegal format (resolution)\n";
40 return;
41 }
42
43 int openmode = mode == WRITE ? O_WRONLY : O_RDONLY;
44 fd = open (name, openmode, 0);
45 if (fd == -1) {
46 cerr << "error: Can't open " << name << ": "
47 << strerror (errno) << '\n';
48 return;
49 }
50
51 const int want_buffer_size = get_bytes_per_frame () * buffer_size;
52 int s = (int) (floor (log (want_buffer_size) / log (2.0) + 0.5));
53 if ((1L << s) != want_buffer_size) {
54 cerr << "error: Invalid requested buffer size\n";
55 return;
56 }
57
58 int arg = 0x00020000 + s;
59 if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &arg)) {
60 cerr << "error: Can't set fragment size: "
61 << strerror (errno) << '\n';
62 return;
63 }
64
65 const int want_format = format == S8 ? AFMT_S8 : AFMT_S16_NE;
66 int tmp_format = want_format;
67 if (ioctl (fd, SNDCTL_DSP_SETFMT, &tmp_format) == -1) {
68 cerr << "error: " << strerror (errno) << '\n';
69 return;
70 }
71
72 if (want_format != tmp_format) {
73 cerr << "error: Can't set requested format (resolution)\n";
74 return;
75 }
76
77 const int want_stereo = channels == 1 ? 0 : 1;
78 int tmp_stereo = want_stereo;
79 if (ioctl (fd, SNDCTL_DSP_STEREO, &tmp_stereo) == -1) {
80 cerr << "error: " << strerror (errno) << '\n';
81 return;
82 }
83
84 if (want_stereo != tmp_stereo) {
85 cerr << "error: Can't set mono/stereo\n";
86 return;
87 }
88
89 int tmp_rate = rate;
90 if (ioctl (fd, SNDCTL_DSP_SPEED, &tmp_rate) == -1) {
91 cerr << "error: " << strerror (errno) << '\n';
92 return;
93 }
94
95 if (abs (rate - tmp_rate) > 1) { // we can tolerate 1 Hz difference
96 cerr << "error: Can't set requested rate\n"
97 << "requested rate: " << rate << " Hz, actual rate: "
98 << tmp_rate << " Hz\n";
99 return;
100 }
101
102 int tmp_buffer_size = want_buffer_size;
103 if (ioctl (fd, SNDCTL_DSP_SETBLKSIZE, &tmp_buffer_size) == -1 ||
104 ioctl (fd, SNDCTL_DSP_GETBLKSIZE, &tmp_buffer_size) == -1) {
105 cerr << "error " << strerror (errno) << '\n';
106 return;
107 }
108
109 if (want_buffer_size != tmp_buffer_size) {
110 cerr << "error: Can't set requested buffer size\n"
111 << "requested size: " << want_buffer_size << " bytes, actual size: "
112 << tmp_buffer_size << " bytes\n";
113 return;
114 }
115
116 ok = true;
117 }
118
119
~PCMOSS()120 PCMOSS::~PCMOSS ()
121 {
122 if (fd > 0)
123 close (fd);
124 }
125
126
127 void
info() const128 PCMOSS::info () const
129 {
130 cerr << "driver: oss\n";
131 PCM::info ();
132 }
133
134
135 size_t
size()136 PCMOSS::size ()
137 {
138 return (size_t)(-1);
139 }
140
141
142 off_t
seek(off_t,int)143 PCMOSS::seek (off_t, int)
144 {
145 return (off_t)(-1);
146 }
147
148
149 size_t
read(void * buffer,size_t frames)150 PCMOSS::read (void* buffer, size_t frames)
151 {
152 int i = get_bytes_per_frame () * frames;
153
154 if (::read (fd, buffer, i) != i) {
155 cerr << "error: " << strerror (errno) << '\n';
156 return (size_t)(-1);
157 }
158
159 return frames;
160 }
161
162
163 size_t
write(void * buffer,size_t frames)164 PCMOSS::write (void* buffer, size_t frames)
165 {
166 int i = get_bytes_per_frame () * frames;
167
168 if (::write (fd, buffer, i) != i) {
169 cerr << "error: " << strerror (errno) << '\n';
170 return (size_t)(-1);
171 }
172
173 return frames;
174 }
175