2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
40 #include "backends/base.h"
42 #include <sys/audioio.h>
45 typedef struct ALCsolarisBackend
{
46 DERIVE_FROM_TYPE(ALCbackend
);
57 static int ALCsolarisBackend_mixerProc(void *ptr
);
59 static void ALCsolarisBackend_Construct(ALCsolarisBackend
*self
, ALCdevice
*device
);
60 static void ALCsolarisBackend_Destruct(ALCsolarisBackend
*self
);
61 static ALCenum
ALCsolarisBackend_open(ALCsolarisBackend
*self
, const ALCchar
*name
);
62 static void ALCsolarisBackend_close(ALCsolarisBackend
*self
);
63 static ALCboolean
ALCsolarisBackend_reset(ALCsolarisBackend
*self
);
64 static ALCboolean
ALCsolarisBackend_start(ALCsolarisBackend
*self
);
65 static void ALCsolarisBackend_stop(ALCsolarisBackend
*self
);
66 static DECLARE_FORWARD2(ALCsolarisBackend
, ALCbackend
, ALCenum
, captureSamples
, void*, ALCuint
)
67 static DECLARE_FORWARD(ALCsolarisBackend
, ALCbackend
, ALCuint
, availableSamples
)
68 static DECLARE_FORWARD(ALCsolarisBackend
, ALCbackend
, ClockLatency
, getClockLatency
)
69 static DECLARE_FORWARD(ALCsolarisBackend
, ALCbackend
, void, lock
)
70 static DECLARE_FORWARD(ALCsolarisBackend
, ALCbackend
, void, unlock
)
71 DECLARE_DEFAULT_ALLOCATORS(ALCsolarisBackend
)
73 DEFINE_ALCBACKEND_VTABLE(ALCsolarisBackend
);
76 static const ALCchar solaris_device
[] = "Solaris Default";
78 static const char *solaris_driver
= "/dev/audio";
81 static void ALCsolarisBackend_Construct(ALCsolarisBackend
*self
, ALCdevice
*device
)
83 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
84 SET_VTABLE2(ALCsolarisBackend
, ALCbackend
, self
);
89 static void ALCsolarisBackend_Destruct(ALCsolarisBackend
*self
)
96 self
->mix_data
= NULL
;
99 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
103 static int ALCsolarisBackend_mixerProc(void *ptr
)
105 ALCsolarisBackend
*self
= ptr
;
106 ALCdevice
*Device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
111 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
113 frameSize
= FrameSizeFromDevFmt(Device
->FmtChans
, Device
->FmtType
);
115 while(!self
->killNow
&& Device
->Connected
)
117 ALint len
= self
->data_size
;
118 ALubyte
*WritePtr
= self
->mix_data
;
120 aluMixData(Device
, WritePtr
, len
/frameSize
);
121 while(len
> 0 && !self
->killNow
)
123 wrote
= write(self
->fd
, WritePtr
, len
);
126 if(errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
&& errno
!= EINTR
)
128 ERR("write failed: %s\n", strerror(errno
));
129 ALCsolarisBackend_lock(self
);
130 aluHandleDisconnect(Device
);
131 ALCsolarisBackend_unlock(self
);
148 static ALCenum
ALCsolarisBackend_open(ALCsolarisBackend
*self
, const ALCchar
*name
)
153 name
= solaris_device
;
154 else if(strcmp(name
, solaris_device
) != 0)
155 return ALC_INVALID_VALUE
;
157 self
->fd
= open(solaris_driver
, O_WRONLY
);
160 ERR("Could not open %s: %s\n", solaris_driver
, strerror(errno
));
161 return ALC_INVALID_VALUE
;
164 device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
165 al_string_copy_cstr(&device
->DeviceName
, name
);
170 static void ALCsolarisBackend_close(ALCsolarisBackend
*self
)
176 static ALCboolean
ALCsolarisBackend_reset(ALCsolarisBackend
*self
)
178 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
183 AUDIO_INITINFO(&info
);
185 info
.play
.sample_rate
= device
->Frequency
;
187 if(device
->FmtChans
!= DevFmtMono
)
188 device
->FmtChans
= DevFmtStereo
;
189 numChannels
= ChannelsFromDevFmt(device
->FmtChans
);
190 info
.play
.channels
= numChannels
;
192 switch(device
->FmtType
)
195 info
.play
.precision
= 8;
196 info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
199 info
.play
.precision
= 8;
200 info
.play
.encoding
= AUDIO_ENCODING_LINEAR8
;
206 device
->FmtType
= DevFmtShort
;
209 info
.play
.precision
= 16;
210 info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
214 frameSize
= numChannels
* BytesFromDevFmt(device
->FmtType
);
215 info
.play
.buffer_size
= device
->UpdateSize
*device
->NumUpdates
* frameSize
;
217 if(ioctl(self
->fd
, AUDIO_SETINFO
, &info
) < 0)
219 ERR("ioctl failed: %s\n", strerror(errno
));
223 if(ChannelsFromDevFmt(device
->FmtChans
) != info
.play
.channels
)
225 ERR("Could not set %d channels, got %d instead\n", ChannelsFromDevFmt(device
->FmtChans
), info
.play
.channels
);
229 if(!((info
.play
.precision
== 8 && info
.play
.encoding
== AUDIO_ENCODING_LINEAR8
&& device
->FmtType
== DevFmtUByte
) ||
230 (info
.play
.precision
== 8 && info
.play
.encoding
== AUDIO_ENCODING_LINEAR
&& device
->FmtType
== DevFmtByte
) ||
231 (info
.play
.precision
== 16 && info
.play
.encoding
== AUDIO_ENCODING_LINEAR
&& device
->FmtType
== DevFmtShort
) ||
232 (info
.play
.precision
== 32 && info
.play
.encoding
== AUDIO_ENCODING_LINEAR
&& device
->FmtType
== DevFmtInt
)))
234 ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(device
->FmtType
),
235 info
.play
.precision
, info
.play
.encoding
);
239 device
->Frequency
= info
.play
.sample_rate
;
240 device
->UpdateSize
= (info
.play
.buffer_size
/device
->NumUpdates
) + 1;
242 SetDefaultChannelOrder(device
);
244 free(self
->mix_data
);
245 self
->data_size
= device
->UpdateSize
* FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
246 self
->mix_data
= calloc(1, self
->data_size
);
251 static ALCboolean
ALCsolarisBackend_start(ALCsolarisBackend
*self
)
254 if(althrd_create(&self
->thread
, ALCsolarisBackend_mixerProc
, self
) != althrd_success
)
259 static void ALCsolarisBackend_stop(ALCsolarisBackend
*self
)
267 althrd_join(self
->thread
, &res
);
269 if(ioctl(self
->fd
, AUDIO_DRAIN
) < 0)
270 ERR("Error draining device: %s\n", strerror(errno
));
274 typedef struct ALCsolarisBackendFactory
{
275 DERIVE_FROM_TYPE(ALCbackendFactory
);
276 } ALCsolarisBackendFactory
;
277 #define ALCSOLARISBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsolarisBackendFactory, ALCbackendFactory) } }
279 ALCbackendFactory
*ALCsolarisBackendFactory_getFactory(void);
281 static ALCboolean
ALCsolarisBackendFactory_init(ALCsolarisBackendFactory
*self
);
282 static DECLARE_FORWARD(ALCsolarisBackendFactory
, ALCbackendFactory
, void, deinit
)
283 static ALCboolean
ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory
*self
, ALCbackend_Type type
);
284 static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory
*self
, enum DevProbe type
);
285 static ALCbackend
* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
286 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsolarisBackendFactory
);
289 ALCbackendFactory
*ALCsolarisBackendFactory_getFactory(void)
291 static ALCsolarisBackendFactory factory
= ALCSOLARISBACKENDFACTORY_INITIALIZER
;
292 return STATIC_CAST(ALCbackendFactory
, &factory
);
296 static ALCboolean
ALCsolarisBackendFactory_init(ALCsolarisBackendFactory
* UNUSED(self
))
298 ConfigValueStr(NULL
, "solaris", "device", &solaris_driver
);
302 static ALCboolean
ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
304 if(type
== ALCbackend_Playback
)
309 static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory
* UNUSED(self
), enum DevProbe type
)
313 case ALL_DEVICE_PROBE
:
317 if(stat(solaris_driver
, &buf
) == 0)
319 AppendAllDevicesList(solaris_device
);
323 case CAPTURE_DEVICE_PROBE
:
328 ALCbackend
* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
330 if(type
== ALCbackend_Playback
)
332 ALCsolarisBackend
*backend
;
333 NEW_OBJ(backend
, ALCsolarisBackend
)(device
);
334 if(!backend
) return NULL
;
335 return STATIC_CAST(ALCbackend
, backend
);