]> git.saurik.com Git - wxWidgets.git/blob - utils/wxMMedia/snduss.cpp
* Fixes
[wxWidgets.git] / utils / wxMMedia / snduss.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2 // Name: snduss.cpp
3 // Purpose: wxMMedia
4 // Author: Guilhem Lavaux
5 // Created: 1997
6 // Updated: 1998
7 // Copyright: (C) 1997, 1998, Guilhem Lavaux
8 // License: wxWindows license
9 ////////////////////////////////////////////////////////////////////////////////
10 #ifdef __GNUG__
11 #pragma implementation "snduss.h"
12 #endif
13
14 #include <sys/soundcard.h>
15 #include <sys/ioctl.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <time.h>
19
20 #include "wx/app.h"
21 #include "wx/utils.h"
22
23 #define WXMMEDIA_INTERNAL
24 #include "snduss.h"
25 #include "sndfrmt.h"
26
27 wxUssSound::wxUssSound()
28 : wxSound(),
29 m_srate(0), m_bps(0), m_stereo(0),
30 m_mode(wxSND_OTHER_IO),
31 m_stop_thrd(TRUE), m_sleeping(FALSE)
32 {
33 m_fd = -1;
34 m_ussformat.SetCodecNo(WXSOUND_PCM);
35 m_ussformat.SetSign(wxSND_SAMPLE_SIGNED);
36 m_ussformat.SetByteOrder(wxSND_SAMPLE_LE);
37
38 m_sndbuf = new wxStreamBuffer(wxStreamBuffer::read_write);
39 m_sndbuf->Flushable(FALSE);
40 m_sndbuf->Fixed(TRUE);
41 }
42
43 wxUssSound::~wxUssSound()
44 {
45 if (!m_stop_thrd) {
46 m_stop_thrd = TRUE;
47 if (m_sleeping) {
48 m_sleep_mtx.Lock();
49 m_sleep_cond.Signal();
50 m_sleep_mtx.Unlock();
51 }
52 Join();
53 }
54
55 if (m_fd != -1)
56 close(m_fd);
57 }
58
59 bool wxUssSound::Wakeup(wxSndBuffer& WXUNUSED(buf))
60 {
61 printf("Waking up (wxUssSound::Wakeup) ...\n");
62 if (m_stop_thrd) {
63 m_stop_thrd = FALSE;
64 Entry();
65 // wxThread::Create();
66 }
67
68 if (m_sleeping) {
69 m_sleep_mtx.Lock();
70 m_sleep_cond.Signal();
71 m_sleep_mtx.Unlock();
72 }
73
74 return TRUE;
75 }
76
77 void wxUssSound::StopBuffer(wxSndBuffer& buf)
78 {
79 buf.HardLock();
80 buf.Set(wxSND_BUFSTOP);
81 buf.HardUnlock();
82 while (buf.IsSet(wxSND_BUFSTOP))
83 wxYield();
84 // usleep(0);
85 }
86
87 void wxUssSound::USS_Sleep()
88 {
89 bool ret;
90
91 printf("Asleeping ...\n");
92 m_sleeping = TRUE;
93 m_sleep_mtx.Lock();
94 ret = m_sleep_cond.Wait(m_sleep_mtx, 10, 0);
95 m_sleep_mtx.Unlock();
96 m_sleeping = FALSE;
97
98 printf("Waking up ...\n");
99 if (!ret)
100 m_stop_thrd = TRUE;
101 }
102
103 bool wxUssSound::DoInput(wxSndBuffer *buf)
104 {
105 wxUint32 bufsize;
106 wxSoundCodec *codec = buf->GetFormat().GetCodec();
107
108 m_sndbuf->ResetBuffer();
109 codec->SetInStream(m_sndbuf);
110 codec->InitIO(m_ussformat);
111
112 bufsize = codec->Available();
113 if (bufsize > m_max_bufsize)
114 bufsize = m_max_bufsize;
115
116 if (!bufsize) {
117 buf->Clear(wxSND_BUFLOCKED | wxSND_BUFREADY);
118 return false;
119 }
120 read(m_fd, m_sndbuf, bufsize);
121 codec->Encode();
122
123 return true;
124 }
125
126 bool wxUssSound::DoOutput(wxSndBuffer *buf)
127 {
128 wxSoundCodec *codec = buf->GetCurrentCodec();
129
130 m_sndbuf->ResetBuffer();
131 codec->SetOutStream(m_sndbuf);
132 codec->InitIO(m_ussformat);
133
134 if (!codec->Available()) {
135 buf->Clear(wxSND_BUFLOCKED | wxSND_BUFREADY);
136 return false;
137 }
138 codec->Decode();
139 write(m_fd, m_sndbuf, m_sndbuf->GetIntPosition());
140
141 // Well ... it's not accurate ! :-|
142 buf->OnBufferOutFinished();
143
144 return true;
145 }
146
147 void *wxUssSound::Entry()
148 {
149 wxNode *node;
150 wxSndBuffer *buf;
151
152 while (!m_stop_thrd) {
153 node = m_buffers.First();
154 if (!node) {
155 USS_Sleep();
156 continue;
157 }
158 buf = (wxSndBuffer *)node->Data();
159 if (!OnSetupDriver(*buf, buf->GetMode()))
160 continue;
161
162 buf->HardLock();
163 if (buf->IsSet(wxSND_BUFSTOP)) {
164 buf->HardUnlock();
165 delete node;
166 continue;
167 }
168 switch(m_mode) {
169 case wxSND_INPUT:
170 if (!DoInput(buf))
171 delete node;
172 break;
173 case wxSND_OUTPUT:
174 if (!DoOutput(buf))
175 delete node;
176 break;
177 case wxSND_DUPLEX:
178 case wxSND_OTHER_IO:
179 break;
180 }
181 buf->HardUnlock();
182 }
183 return NULL;
184 }
185
186 bool wxUssSound::OnSetupDriver(wxSndBuffer& buf, wxSndMode WXUNUSED(mode))
187 {
188 wxSoundDataFormat format;
189 wxSoundCodec *codec;
190
191 codec = buf.GetFormat().GetCodec();
192 format = codec->GetPreferredFormat(WXSOUND_PCM);
193
194 if ((format.GetSampleRate() != m_srate) ||
195 (format.GetBps() != m_bps) ||
196 (format.GetStereo() != m_stereo)) {
197
198 if (!SetupSound(format.GetSampleRate(), format.GetBps(),
199 format.GetStereo())) {
200 m_buffers.DeleteObject(&buf);
201 buf.Clear(wxSND_BUFLOCKED | wxSND_BUFREADY);
202 buf.SetError(wxSND_CANTSET);
203 return false;
204 }
205 m_mode = wxSND_OTHER_IO;
206 }
207
208 if (buf.GetMode() != m_mode) {
209 m_mode = buf.GetMode();
210 return false;
211 }
212
213 return true;
214 }
215
216 wxUint32 wxUssSound::GetNbFragments()
217 {
218 struct audio_buf_info frag_info;
219
220 ioctl(m_fd, SNDCTL_DSP_GETOSPACE, &frag_info);
221
222 return frag_info.fragstotal;
223 }
224
225 wxUint32 wxUssSound::GetFragmentSize()
226 {
227 return m_max_bufsize;
228 }
229
230 bool wxUssSound::SetupSound(wxUint16 srate, wxUint8 bps, bool stereo)
231 {
232 int tmp;
233 unsigned long tmp_ul;
234
235 if (m_fd != -1) {
236 delete m_sndbuf;
237 fsync(m_fd);
238 close(m_fd);
239 }
240
241 m_fd = open("/dev/dsp", O_RDWR);
242
243 tmp = stereo;
244 if (ioctl(m_fd, SNDCTL_DSP_STEREO, &tmp) < 0)
245 return FALSE;
246 m_stereo = tmp;
247
248 tmp_ul = srate;
249 if (ioctl(m_fd, SNDCTL_DSP_SPEED, &tmp_ul) < 0)
250 return FALSE;
251 m_srate = tmp_ul;
252
253 tmp = bps;
254 if (ioctl(m_fd, SNDCTL_DSP_SAMPLESIZE, &tmp) < 0)
255 return FALSE;
256 m_bps = tmp;
257
258 ioctl(m_fd, SNDCTL_DSP_GETBLKSIZE, &tmp);
259 m_max_bufsize = tmp;
260 m_sndbuf->SetBufferIO(m_max_bufsize);
261
262 m_ussformat.SetBps(m_bps);
263 m_ussformat.SetChannels((m_stereo) ? 2 : 1);
264 m_ussformat.SetSampleRate(m_srate);
265
266 return TRUE;
267 }