Change the backend getLatency method to return the clock time too
[openal-soft.git] / Alc / backends / null.c
blob5b153cd9742500b5d60dcd129c31c3dd78a1c40f
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 2010 by Chris Robinson
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
21 #include "config.h"
23 #include <stdlib.h>
24 #ifdef HAVE_WINDOWS_H
25 #include <windows.h>
26 #endif
28 #include "alMain.h"
29 #include "alu.h"
30 #include "threads.h"
31 #include "compat.h"
33 #include "backends/base.h"
36 typedef struct ALCnullBackend {
37 DERIVE_FROM_TYPE(ALCbackend);
39 volatile int killNow;
40 althrd_t thread;
41 } ALCnullBackend;
43 static int ALCnullBackend_mixerProc(void *ptr);
45 static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device);
46 static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, Destruct)
47 static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name);
48 static void ALCnullBackend_close(ALCnullBackend *self);
49 static ALCboolean ALCnullBackend_reset(ALCnullBackend *self);
50 static ALCboolean ALCnullBackend_start(ALCnullBackend *self);
51 static void ALCnullBackend_stop(ALCnullBackend *self);
52 static DECLARE_FORWARD2(ALCnullBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
53 static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALCuint, availableSamples)
54 static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ClockLatency, getClockLatency)
55 static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, lock)
56 static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, unlock)
57 DECLARE_DEFAULT_ALLOCATORS(ALCnullBackend)
59 DEFINE_ALCBACKEND_VTABLE(ALCnullBackend);
62 static const ALCchar nullDevice[] = "No Output";
65 static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device)
67 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
68 SET_VTABLE2(ALCnullBackend, ALCbackend, self);
72 static int ALCnullBackend_mixerProc(void *ptr)
74 ALCnullBackend *self = (ALCnullBackend*)ptr;
75 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
76 struct timespec now, start;
77 ALuint64 avail, done;
78 const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 /
79 device->Frequency / 2);
81 SetRTPriority();
82 althrd_setname(althrd_current(), MIXER_THREAD_NAME);
84 done = 0;
85 if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC)
87 ERR("Failed to get starting time\n");
88 return 1;
90 while(!self->killNow && device->Connected)
92 if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
94 ERR("Failed to get current time\n");
95 return 1;
98 avail = (now.tv_sec - start.tv_sec) * device->Frequency;
99 avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000;
100 if(avail < done)
102 /* Oops, time skipped backwards. Reset the number of samples done
103 * with one update available since we (likely) just came back from
104 * sleeping. */
105 done = avail - device->UpdateSize;
108 if(avail-done < device->UpdateSize)
109 al_nssleep(restTime);
110 else while(avail-done >= device->UpdateSize)
112 aluMixData(device, NULL, device->UpdateSize);
113 done += device->UpdateSize;
117 return 0;
121 static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name)
123 ALCdevice *device;
125 if(!name)
126 name = nullDevice;
127 else if(strcmp(name, nullDevice) != 0)
128 return ALC_INVALID_VALUE;
130 device = STATIC_CAST(ALCbackend, self)->mDevice;
131 al_string_copy_cstr(&device->DeviceName, name);
133 return ALC_NO_ERROR;
136 static void ALCnullBackend_close(ALCnullBackend* UNUSED(self))
140 static ALCboolean ALCnullBackend_reset(ALCnullBackend *self)
142 SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice);
143 return ALC_TRUE;
146 static ALCboolean ALCnullBackend_start(ALCnullBackend *self)
148 self->killNow = 0;
149 if(althrd_create(&self->thread, ALCnullBackend_mixerProc, self) != althrd_success)
150 return ALC_FALSE;
151 return ALC_TRUE;
154 static void ALCnullBackend_stop(ALCnullBackend *self)
156 int res;
158 if(self->killNow)
159 return;
161 self->killNow = 1;
162 althrd_join(self->thread, &res);
166 typedef struct ALCnullBackendFactory {
167 DERIVE_FROM_TYPE(ALCbackendFactory);
168 } ALCnullBackendFactory;
169 #define ALCNULLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCnullBackendFactory, ALCbackendFactory) } }
171 ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
173 static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory *self);
174 static DECLARE_FORWARD(ALCnullBackendFactory, ALCbackendFactory, void, deinit)
175 static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory *self, ALCbackend_Type type);
176 static void ALCnullBackendFactory_probe(ALCnullBackendFactory *self, enum DevProbe type);
177 static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
178 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCnullBackendFactory);
181 ALCbackendFactory *ALCnullBackendFactory_getFactory(void)
183 static ALCnullBackendFactory factory = ALCNULLBACKENDFACTORY_INITIALIZER;
184 return STATIC_CAST(ALCbackendFactory, &factory);
188 static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory* UNUSED(self))
190 return ALC_TRUE;
193 static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory* UNUSED(self), ALCbackend_Type type)
195 if(type == ALCbackend_Playback)
196 return ALC_TRUE;
197 return ALC_FALSE;
200 static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enum DevProbe type)
202 switch(type)
204 case ALL_DEVICE_PROBE:
205 AppendAllDevicesList(nullDevice);
206 break;
207 case CAPTURE_DEVICE_PROBE:
208 break;
212 static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
214 if(type == ALCbackend_Playback)
216 ALCnullBackend *backend;
217 NEW_OBJ(backend, ALCnullBackend)(device);
218 if(!backend) return NULL;
219 return STATIC_CAST(ALCbackend, backend);
222 return NULL;