]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/mmedia/sndesd.cpp
fixed LastRead() after Read(wxOutputStream&) (patch 1658301)
[wxWidgets.git] / contrib / src / mmedia / sndesd.cpp
1 // --------------------------------------------------------------------------
2 // Name: sndesd.cpp
3 // Purpose:
4 // Date: 08/11/1999
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
6 // CVSID: $Id$
7 // wxWindows licence
8 // --------------------------------------------------------------------------
9
10 #include "wx/wxprec.h"
11
12 #ifndef WX_PRECOMP
13 #include "wx/defs.h"
14 #include "wx/string.h"
15 #endif
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 // --------------------------------------------------------------------------
22 // MMedia headers
23 // --------------------------------------------------------------------------
24
25 #include "wx/mmedia/sndbase.h"
26 #include "wx/mmedia/sndesd.h"
27 #include "wx/mmedia/sndpcm.h"
28
29 // --------------------------------------------------------------------------
30 // System headers
31 // --------------------------------------------------------------------------
32
33 #ifdef HAVE_ESD_H
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <esd.h>
38 #ifdef __WXGTK__
39 #include <gdk/gdk.h>
40 #endif
41 #endif
42
43 // --------------------------------------------------------------------------
44
45 #define MY_ESD_NAME "wxWidgets/wxSoundStreamESD"
46
47 // --------------------------------------------------------------------------
48 // wxSoundStreamESD: ESD sound driver
49
50 // --------------------------------------------------------------------------
51 // Constructors/Destructors
52 // --------------------------------------------------------------------------
53
54 wxSoundStreamESD::wxSoundStreamESD(const wxString& hostname)
55 {
56 #ifndef HAVE_ESD_H
57 m_snderror = wxSOUND_INVDEV;
58 return;
59 #else
60 wxSoundFormatPcm pcm_default;
61
62 // First, we make some basic test: is there ESD on this computer ?
63 m_esd_ok = false;
64
65 if (hostname.IsNull())
66 m_fd_output = esd_play_stream(ESD_PLAY | ESD_STREAM, 22050,
67 hostname.mb_str(), MY_ESD_NAME);
68 else
69 m_fd_output = esd_play_stream(ESD_PLAY | ESD_STREAM, 22050,
70 NULL, MY_ESD_NAME);
71 if (m_fd_output == -1) {
72 // Answer: no. We return with an error.
73 m_snderror = wxSOUND_INVDEV;
74 return;
75 }
76
77 // Close this unuseful stream.
78 esd_close(m_fd_output);
79
80 m_hostname = hostname;
81
82 // Set the default audio format
83 SetSoundFormat(pcm_default);
84
85 // Initialize some variable
86 m_snderror = wxSOUND_NOERROR;
87 m_esd_stop = true;
88 m_q_filled = true;
89 m_esd_ok = true;
90 m_fd_output= -1;
91 m_fd_input = -1;
92 #endif // defined HAVE_ESD_H
93 }
94
95 wxSoundStreamESD::~wxSoundStreamESD()
96 {
97 #ifdef HAVE_ESD_H
98 if (!m_esd_stop)
99 StopProduction();
100 #endif // defined HAVE_ESD_H
101 }
102
103 // --------------------------------------------------------------------------
104 // Read several samples
105 // --------------------------------------------------------------------------
106
107 wxSoundStream& wxSoundStreamESD::Read(void *buffer, wxUint32 len)
108 {
109 #ifndef HAVE_ESD_H
110 m_snderror = wxSOUND_INVDEV;
111 return *this;
112 #else
113 int ret;
114
115 if (m_esd_stop) {
116 m_snderror = wxSOUND_NOTSTARTED;
117 return *this;
118 }
119
120 ret = read(m_fd_input, buffer, len);
121 m_lastcount = (wxUint32)ret;
122
123 if (ret < 0)
124 m_snderror = wxSOUND_IOERROR;
125 else
126 m_snderror = wxSOUND_NOERROR;
127
128 return *this;
129 #endif // defined HAVE_ESD_H
130 }
131
132 // --------------------------------------------------------------------------
133 // Write several samples
134 // --------------------------------------------------------------------------
135 wxSoundStream& wxSoundStreamESD::Write(const void *buffer, wxUint32 len)
136 {
137 #ifndef HAVE_ESD_H
138 m_snderror = wxSOUND_INVDEV;
139 return *this;
140 #else
141 int ret;
142
143 if (m_esd_stop) {
144 m_lastcount = 0;
145 m_snderror = wxSOUND_NOTSTARTED;
146 return *this;
147 }
148
149 ret = write(m_fd_output, buffer, len);
150 m_lastcount = (wxUint32)ret;
151
152 if (ret < 0)
153 m_snderror = wxSOUND_IOERROR;
154 else
155 m_snderror = wxSOUND_NOERROR;
156
157 m_q_filled = true;
158
159 return *this;
160 #endif // defined HAVE_ESD_H
161 }
162
163 // --------------------------------------------------------------------------
164 // SetSoundFormat(): this function specifies which format we want and which
165 // format is available
166 // --------------------------------------------------------------------------
167 bool wxSoundStreamESD::SetSoundFormat(const wxSoundFormatBase& format)
168 {
169 #ifndef HAVE_ESD_H
170 m_snderror = wxSOUND_INVDEV;
171 return false;
172 #else
173 wxSoundFormatPcm *pcm_format;
174
175 if (format.GetType() != wxSOUND_PCM) {
176 m_snderror = wxSOUND_INVFRMT;
177 return false;
178 }
179
180 if (!m_esd_ok) {
181 m_snderror = wxSOUND_INVDEV;
182 return false;
183 }
184
185 if (m_sndformat)
186 delete m_sndformat;
187
188 m_sndformat = format.Clone();
189 if (!m_sndformat) {
190 m_snderror = wxSOUND_MEMERROR;
191 return false;
192 }
193 pcm_format = (wxSoundFormatPcm *)m_sndformat;
194
195 // Detect the best format
196 DetectBest(pcm_format);
197
198 m_snderror = wxSOUND_NOERROR;
199 if (*pcm_format != format) {
200 m_snderror = wxSOUND_NOEXACT;
201 return false;
202 }
203 return true;
204 #endif // defined HAVE_ESD_H
205 }
206
207 // --------------------------------------------------------------------------
208 // _wxSound_OSS_CBack (internal): it is called when the driver (ESD) is
209 // ready for a next buffer.
210 // --------------------------------------------------------------------------
211 #if defined(__WXGTK__) && defined(HAVE_ESD_H)
212 static void _wxSound_OSS_CBack(gpointer data, int source,
213 GdkInputCondition condition)
214 {
215 wxSoundStreamESD *esd = (wxSoundStreamESD *)data;
216
217 switch (condition) {
218 case GDK_INPUT_READ:
219 esd->WakeUpEvt(wxSOUND_INPUT);
220 break;
221 case GDK_INPUT_WRITE:
222 esd->WakeUpEvt(wxSOUND_OUTPUT);
223 break;
224 default:
225 break;
226 }
227 }
228 #endif
229
230
231 // --------------------------------------------------------------------------
232 // WakeUpEvt() (internal): it is called by _wxSound_OSS_CBack to bypass the
233 // C++ protection
234 // --------------------------------------------------------------------------
235 void wxSoundStreamESD::WakeUpEvt(int evt)
236 {
237 m_q_filled = false;
238 OnSoundEvent(evt);
239 }
240
241 // --------------------------------------------------------------------------
242 // StartProduction(): see wxSoundStream
243 // --------------------------------------------------------------------------
244 bool wxSoundStreamESD::StartProduction(int evt)
245 {
246 #ifndef HAVE_ESD_H
247 m_snderror = wxSOUND_INVDEV;
248 return false;
249 #else
250 wxSoundFormatPcm *pcm;
251 int flag = 0;
252
253 if (!m_esd_ok) {
254 m_snderror = wxSOUND_INVDEV;
255 return false;
256 }
257
258 if (!m_esd_stop)
259 StopProduction();
260
261 pcm = (wxSoundFormatPcm *)m_sndformat;
262
263 flag |= (pcm->GetBPS() == 16) ? ESD_BITS16 : ESD_BITS8;
264 flag |= (pcm->GetChannels() == 2) ? ESD_STEREO : ESD_MONO;
265
266 if ((evt & wxSOUND_OUTPUT) != 0) {
267 flag |= ESD_PLAY | ESD_STREAM;
268 m_fd_output = esd_play_stream(flag, pcm->GetSampleRate(), NULL,
269 MY_ESD_NAME);
270 }
271
272 if ((evt & wxSOUND_INPUT) != 0) {
273 flag |= ESD_RECORD | ESD_STREAM;
274 m_fd_input = esd_record_stream(flag, pcm->GetSampleRate(), NULL,
275 MY_ESD_NAME);
276 }
277
278 #ifdef __WXGTK__
279 if ((evt & wxSOUND_OUTPUT) != 0) {
280 m_tag_output = gdk_input_add(m_fd_output, GDK_INPUT_WRITE,
281 _wxSound_OSS_CBack, (gpointer)this);
282 }
283 if ((evt & wxSOUND_INPUT) != 0) {
284 m_tag_input = gdk_input_add(m_fd_input, GDK_INPUT_READ,
285 _wxSound_OSS_CBack, (gpointer)this);
286 }
287 #endif
288
289 m_esd_stop = false;
290 m_q_filled = false;
291
292 return true;
293 #endif // defined HAVE_ESD_H
294 }
295
296 // --------------------------------------------------------------------------
297 // StopProduction(): see wxSoundStream
298 // --------------------------------------------------------------------------
299 bool wxSoundStreamESD::StopProduction()
300 {
301 #ifndef HAVE_ESD_H
302 m_snderror = wxSOUND_INVDEV;
303 return false;
304 #else
305 if (m_esd_stop)
306 return false;
307
308 if (m_fd_input != -1) {
309 esd_close(m_fd_input);
310 #ifdef __WXGTK__
311 gdk_input_remove(m_tag_input);
312 #endif
313 }
314 if (m_fd_output != -1) {
315 esd_close(m_fd_output);
316 #ifdef __WXGTK__
317 gdk_input_remove(m_tag_output);
318 #endif
319 }
320
321 m_fd_input = -1;
322 m_fd_output= -1;
323 m_esd_stop = true;
324 m_q_filled = true;
325 return true;
326 #endif // defined HAVE_ESD_H
327 }
328
329 //
330 // Detect the closest format (The best).
331 //
332 void wxSoundStreamESD::DetectBest(wxSoundFormatPcm *pcm)
333 {
334 #ifndef HAVE_ESD_H
335 m_snderror = wxSOUND_INVDEV;
336 return;
337 #else
338 wxSoundFormatPcm best_pcm;
339
340 // We change neither the number of channels nor the sample rate
341 // because ESD is clever.
342
343 best_pcm.SetSampleRate(pcm->GetSampleRate());
344 best_pcm.SetChannels(pcm->GetChannels());
345
346 // It supports 16 bits
347 if (pcm->GetBPS() >= 16)
348 best_pcm.SetBPS(16);
349 else
350 best_pcm.SetBPS(8);
351
352 best_pcm.SetOrder(wxLITTLE_ENDIAN);
353 best_pcm.Signed(true);
354
355 // Finally recopy the new format
356 *pcm = best_pcm;
357 #endif // defined HAVE_ESD_H
358 }
359