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