Added support of AL_LOOP_COUNT Source parameter
[platform/upstream/openal-soft.git] / OpenAL32 / alSource.c
1 /**
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.
8  *
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.
13  *
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
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <math.h>
26 #include <float.h>
27
28 #include "AL/al.h"
29 #include "AL/alc.h"
30 #include "alMain.h"
31 #include "alError.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alThunk.h"
35 #include "alAuxEffectSlot.h"
36
37 #include "backends/base.h"
38
39 #include "threads.h"
40
41
42 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
43 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
44
45 static ALvoid InitSourceParams(ALsource *Source);
46 static ALint64 GetSourceSampleOffset(ALsource *Source);
47 static ALdouble GetSourceSecOffset(ALsource *Source);
48 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
49 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
50
51 typedef enum SourceProp {
52     srcPitch = AL_PITCH,
53     srcGain = AL_GAIN,
54     srcMinGain = AL_MIN_GAIN,
55     srcMaxGain = AL_MAX_GAIN,
56     srcMaxDistance = AL_MAX_DISTANCE,
57     srcRolloffFactor = AL_ROLLOFF_FACTOR,
58     srcDopplerFactor = AL_DOPPLER_FACTOR,
59     srcConeOuterGain = AL_CONE_OUTER_GAIN,
60     srcSecOffset = AL_SEC_OFFSET,
61     srcSampleOffset = AL_SAMPLE_OFFSET,
62     srcByteOffset = AL_BYTE_OFFSET,
63     srcConeInnerAngle = AL_CONE_INNER_ANGLE,
64     srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
65     srcRefDistance = AL_REFERENCE_DISTANCE,
66
67     srcPosition = AL_POSITION,
68     srcVelocity = AL_VELOCITY,
69     srcDirection = AL_DIRECTION,
70
71     srcSourceRelative = AL_SOURCE_RELATIVE,
72     srcLooping = AL_LOOPING,
73     srcBuffer = AL_BUFFER,
74     srcSourceState = AL_SOURCE_STATE,
75     srcBuffersQueued = AL_BUFFERS_QUEUED,
76     srcBuffersProcessed = AL_BUFFERS_PROCESSED,
77     srcSourceType = AL_SOURCE_TYPE,
78
79     /* ALC_EXT_EFX */
80     srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
81     srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
82     srcRoomRolloffFactor =  AL_ROOM_ROLLOFF_FACTOR,
83     srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
84     srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
85     srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
86     srcDirectFilter = AL_DIRECT_FILTER,
87     srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
88
89     /* AL_SOFT_direct_channels */
90     srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
91
92     /* AL_EXT_source_distance_model */
93     srcDistanceModel = AL_DISTANCE_MODEL,
94
95     srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
96     srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
97     srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
98
99     /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
100     srcSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
101     srcByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
102
103     /* AL_SOFT_source_latency */
104     srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
105     srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
106
107     /* AL_EXT_BFORMAT */
108     srcOrientation = AL_ORIENTATION,
109 } SourceProp;
110
111 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
112 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
113 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
114
115 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
116 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
117 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
118
119 static ALint FloatValsByProp(ALenum prop)
120 {
121     if(prop != (ALenum)((SourceProp)prop))
122         return 0;
123     switch((SourceProp)prop)
124     {
125         case AL_PITCH:
126         case AL_GAIN:
127         case AL_MIN_GAIN:
128         case AL_MAX_GAIN:
129         case AL_MAX_DISTANCE:
130         case AL_ROLLOFF_FACTOR:
131         case AL_DOPPLER_FACTOR:
132         case AL_CONE_OUTER_GAIN:
133         case AL_SEC_OFFSET:
134         case AL_SAMPLE_OFFSET:
135         case AL_BYTE_OFFSET:
136         case AL_CONE_INNER_ANGLE:
137         case AL_CONE_OUTER_ANGLE:
138         case AL_REFERENCE_DISTANCE:
139         case AL_CONE_OUTER_GAINHF:
140         case AL_AIR_ABSORPTION_FACTOR:
141         case AL_ROOM_ROLLOFF_FACTOR:
142         case AL_DIRECT_FILTER_GAINHF_AUTO:
143         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
144         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
145         case AL_DIRECT_CHANNELS_SOFT:
146         case AL_DISTANCE_MODEL:
147         case AL_SOURCE_RELATIVE:
148         case AL_LOOPING:
149         case AL_SOURCE_STATE:
150         case AL_BUFFERS_QUEUED:
151         case AL_BUFFERS_PROCESSED:
152         case AL_SOURCE_TYPE:
153         case AL_BYTE_LENGTH_SOFT:
154         case AL_SAMPLE_LENGTH_SOFT:
155         case AL_SEC_LENGTH_SOFT:
156             return 1;
157
158         case AL_SAMPLE_RW_OFFSETS_SOFT:
159         case AL_BYTE_RW_OFFSETS_SOFT:
160             return 2;
161
162         case AL_POSITION:
163         case AL_VELOCITY:
164         case AL_DIRECTION:
165             return 3;
166
167         case AL_ORIENTATION:
168             return 6;
169
170         case AL_SEC_OFFSET_LATENCY_SOFT:
171             break; /* Double only */
172
173         case AL_BUFFER:
174         case AL_DIRECT_FILTER:
175         case AL_AUXILIARY_SEND_FILTER:
176             break; /* i/i64 only */
177         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
178             break; /* i64 only */
179     }
180     return 0;
181 }
182 static ALint DoubleValsByProp(ALenum prop)
183 {
184     if(prop != (ALenum)((SourceProp)prop))
185         return 0;
186     switch((SourceProp)prop)
187     {
188         case AL_PITCH:
189         case AL_GAIN:
190         case AL_MIN_GAIN:
191         case AL_MAX_GAIN:
192         case AL_MAX_DISTANCE:
193         case AL_ROLLOFF_FACTOR:
194         case AL_DOPPLER_FACTOR:
195         case AL_CONE_OUTER_GAIN:
196         case AL_SEC_OFFSET:
197         case AL_SAMPLE_OFFSET:
198         case AL_BYTE_OFFSET:
199         case AL_CONE_INNER_ANGLE:
200         case AL_CONE_OUTER_ANGLE:
201         case AL_REFERENCE_DISTANCE:
202         case AL_CONE_OUTER_GAINHF:
203         case AL_AIR_ABSORPTION_FACTOR:
204         case AL_ROOM_ROLLOFF_FACTOR:
205         case AL_DIRECT_FILTER_GAINHF_AUTO:
206         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
207         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
208         case AL_DIRECT_CHANNELS_SOFT:
209         case AL_DISTANCE_MODEL:
210         case AL_SOURCE_RELATIVE:
211         case AL_LOOPING:
212         case AL_SOURCE_STATE:
213         case AL_BUFFERS_QUEUED:
214         case AL_BUFFERS_PROCESSED:
215         case AL_SOURCE_TYPE:
216         case AL_BYTE_LENGTH_SOFT:
217         case AL_SAMPLE_LENGTH_SOFT:
218         case AL_SEC_LENGTH_SOFT:
219             return 1;
220
221         case AL_SAMPLE_RW_OFFSETS_SOFT:
222         case AL_BYTE_RW_OFFSETS_SOFT:
223         case AL_SEC_OFFSET_LATENCY_SOFT:
224             return 2;
225
226         case AL_POSITION:
227         case AL_VELOCITY:
228         case AL_DIRECTION:
229             return 3;
230
231         case AL_ORIENTATION:
232             return 6;
233
234         case AL_BUFFER:
235         case AL_DIRECT_FILTER:
236         case AL_AUXILIARY_SEND_FILTER:
237             break; /* i/i64 only */
238         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
239             break; /* i64 only */
240     }
241     return 0;
242 }
243
244 static ALint IntValsByProp(ALenum prop)
245 {
246     if(prop != (ALenum)((SourceProp)prop))
247         return 0;
248     switch((SourceProp)prop)
249     {
250         case AL_PITCH:
251         case AL_GAIN:
252         case AL_MIN_GAIN:
253         case AL_MAX_GAIN:
254         case AL_MAX_DISTANCE:
255         case AL_ROLLOFF_FACTOR:
256         case AL_DOPPLER_FACTOR:
257         case AL_CONE_OUTER_GAIN:
258         case AL_SEC_OFFSET:
259         case AL_SAMPLE_OFFSET:
260         case AL_BYTE_OFFSET:
261         case AL_CONE_INNER_ANGLE:
262         case AL_CONE_OUTER_ANGLE:
263         case AL_REFERENCE_DISTANCE:
264         case AL_CONE_OUTER_GAINHF:
265         case AL_AIR_ABSORPTION_FACTOR:
266         case AL_ROOM_ROLLOFF_FACTOR:
267         case AL_DIRECT_FILTER_GAINHF_AUTO:
268         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
269         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
270         case AL_DIRECT_CHANNELS_SOFT:
271         case AL_DISTANCE_MODEL:
272         case AL_SOURCE_RELATIVE:
273         case AL_LOOPING:
274 #ifdef __TIZEN__
275         case AL_LOOP_COUNT:
276 #endif
277         case AL_BUFFER:
278         case AL_SOURCE_STATE:
279         case AL_BUFFERS_QUEUED:
280         case AL_BUFFERS_PROCESSED:
281         case AL_SOURCE_TYPE:
282         case AL_DIRECT_FILTER:
283         case AL_BYTE_LENGTH_SOFT:
284         case AL_SAMPLE_LENGTH_SOFT:
285         case AL_SEC_LENGTH_SOFT:
286             return 1;
287
288         case AL_SAMPLE_RW_OFFSETS_SOFT:
289         case AL_BYTE_RW_OFFSETS_SOFT:
290             return 2;
291
292         case AL_POSITION:
293         case AL_VELOCITY:
294         case AL_DIRECTION:
295         case AL_AUXILIARY_SEND_FILTER:
296             return 3;
297
298         case AL_ORIENTATION:
299             return 6;
300
301         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
302             break; /* i64 only */
303         case AL_SEC_OFFSET_LATENCY_SOFT:
304             break; /* Double only */
305     }
306     return 0;
307 }
308 static ALint Int64ValsByProp(ALenum prop)
309 {
310     if(prop != (ALenum)((SourceProp)prop))
311         return 0;
312     switch((SourceProp)prop)
313     {
314         case AL_PITCH:
315         case AL_GAIN:
316         case AL_MIN_GAIN:
317         case AL_MAX_GAIN:
318         case AL_MAX_DISTANCE:
319         case AL_ROLLOFF_FACTOR:
320         case AL_DOPPLER_FACTOR:
321         case AL_CONE_OUTER_GAIN:
322         case AL_SEC_OFFSET:
323         case AL_SAMPLE_OFFSET:
324         case AL_BYTE_OFFSET:
325         case AL_CONE_INNER_ANGLE:
326         case AL_CONE_OUTER_ANGLE:
327         case AL_REFERENCE_DISTANCE:
328         case AL_CONE_OUTER_GAINHF:
329         case AL_AIR_ABSORPTION_FACTOR:
330         case AL_ROOM_ROLLOFF_FACTOR:
331         case AL_DIRECT_FILTER_GAINHF_AUTO:
332         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
333         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
334         case AL_DIRECT_CHANNELS_SOFT:
335         case AL_DISTANCE_MODEL:
336         case AL_SOURCE_RELATIVE:
337         case AL_LOOPING:
338         case AL_BUFFER:
339         case AL_SOURCE_STATE:
340         case AL_BUFFERS_QUEUED:
341         case AL_BUFFERS_PROCESSED:
342         case AL_SOURCE_TYPE:
343         case AL_DIRECT_FILTER:
344         case AL_BYTE_LENGTH_SOFT:
345         case AL_SAMPLE_LENGTH_SOFT:
346         case AL_SEC_LENGTH_SOFT:
347             return 1;
348
349         case AL_SAMPLE_RW_OFFSETS_SOFT:
350         case AL_BYTE_RW_OFFSETS_SOFT:
351         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
352             return 2;
353
354         case AL_POSITION:
355         case AL_VELOCITY:
356         case AL_DIRECTION:
357         case AL_AUXILIARY_SEND_FILTER:
358             return 3;
359
360         case AL_ORIENTATION:
361             return 6;
362
363         case AL_SEC_OFFSET_LATENCY_SOFT:
364             break; /* Double only */
365     }
366     return 0;
367 }
368
369
370 #define CHECKVAL(x) do {                                                      \
371     if(!(x))                                                                  \
372         SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);      \
373 } while(0)
374
375 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
376 {
377     ALint ival;
378
379     switch(prop)
380     {
381         case AL_BYTE_RW_OFFSETS_SOFT:
382         case AL_SAMPLE_RW_OFFSETS_SOFT:
383         case AL_BYTE_LENGTH_SOFT:
384         case AL_SAMPLE_LENGTH_SOFT:
385         case AL_SEC_LENGTH_SOFT:
386         case AL_SEC_OFFSET_LATENCY_SOFT:
387             /* Query only */
388             SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
389
390         case AL_PITCH:
391             CHECKVAL(*values >= 0.0f);
392
393             Source->Pitch = *values;
394             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
395             return AL_TRUE;
396
397         case AL_CONE_INNER_ANGLE:
398             CHECKVAL(*values >= 0.0f && *values <= 360.0f);
399
400             Source->InnerAngle = *values;
401             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
402             return AL_TRUE;
403
404         case AL_CONE_OUTER_ANGLE:
405             CHECKVAL(*values >= 0.0f && *values <= 360.0f);
406
407             Source->OuterAngle = *values;
408             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
409             return AL_TRUE;
410
411         case AL_GAIN:
412             CHECKVAL(*values >= 0.0f);
413
414             Source->Gain = *values;
415             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
416             return AL_TRUE;
417
418         case AL_MAX_DISTANCE:
419             CHECKVAL(*values >= 0.0f);
420
421             Source->MaxDistance = *values;
422             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
423             return AL_TRUE;
424
425         case AL_ROLLOFF_FACTOR:
426             CHECKVAL(*values >= 0.0f);
427
428             Source->RollOffFactor = *values;
429             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
430             return AL_TRUE;
431
432         case AL_REFERENCE_DISTANCE:
433             CHECKVAL(*values >= 0.0f);
434
435             Source->RefDistance = *values;
436             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
437             return AL_TRUE;
438
439         case AL_MIN_GAIN:
440             CHECKVAL(*values >= 0.0f && *values <= 1.0f);
441
442             Source->MinGain = *values;
443             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
444             return AL_TRUE;
445
446         case AL_MAX_GAIN:
447             CHECKVAL(*values >= 0.0f && *values <= 1.0f);
448
449             Source->MaxGain = *values;
450             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
451             return AL_TRUE;
452
453         case AL_CONE_OUTER_GAIN:
454             CHECKVAL(*values >= 0.0f && *values <= 1.0f);
455
456             Source->OuterGain = *values;
457             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
458             return AL_TRUE;
459
460         case AL_CONE_OUTER_GAINHF:
461             CHECKVAL(*values >= 0.0f && *values <= 1.0f);
462
463             Source->OuterGainHF = *values;
464             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
465             return AL_TRUE;
466
467         case AL_AIR_ABSORPTION_FACTOR:
468             CHECKVAL(*values >= 0.0f && *values <= 10.0f);
469
470             Source->AirAbsorptionFactor = *values;
471             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
472             return AL_TRUE;
473
474         case AL_ROOM_ROLLOFF_FACTOR:
475             CHECKVAL(*values >= 0.0f && *values <= 10.0f);
476
477             Source->RoomRolloffFactor = *values;
478             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
479             return AL_TRUE;
480
481         case AL_DOPPLER_FACTOR:
482             CHECKVAL(*values >= 0.0f && *values <= 1.0f);
483
484             Source->DopplerFactor = *values;
485             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
486             return AL_TRUE;
487
488         case AL_SEC_OFFSET:
489         case AL_SAMPLE_OFFSET:
490         case AL_BYTE_OFFSET:
491             CHECKVAL(*values >= 0.0f);
492
493             LockContext(Context);
494             Source->OffsetType = prop;
495             Source->Offset = *values;
496
497             if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
498                !Context->DeferUpdates)
499             {
500                 WriteLock(&Source->queue_lock);
501                 if(ApplyOffset(Source) == AL_FALSE)
502                 {
503                     WriteUnlock(&Source->queue_lock);
504                     UnlockContext(Context);
505                     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
506                 }
507                 WriteUnlock(&Source->queue_lock);
508             }
509             UnlockContext(Context);
510             return AL_TRUE;
511
512
513         case AL_POSITION:
514             CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
515
516             LockContext(Context);
517             aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f);
518             UnlockContext(Context);
519             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
520             return AL_TRUE;
521
522         case AL_VELOCITY:
523             CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
524
525             LockContext(Context);
526             aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f);
527             UnlockContext(Context);
528             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
529             return AL_TRUE;
530
531         case AL_DIRECTION:
532             CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
533
534             LockContext(Context);
535             aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f);
536             UnlockContext(Context);
537             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
538             return AL_TRUE;
539
540         case AL_ORIENTATION:
541             CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
542                      isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
543
544             LockContext(Context);
545             Source->Orientation[0][0] = values[0];
546             Source->Orientation[0][1] = values[1];
547             Source->Orientation[0][2] = values[2];
548             Source->Orientation[1][0] = values[3];
549             Source->Orientation[1][1] = values[4];
550             Source->Orientation[1][2] = values[5];
551             UnlockContext(Context);
552             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
553             return AL_TRUE;
554
555
556         case AL_SOURCE_RELATIVE:
557         case AL_LOOPING:
558         case AL_SOURCE_STATE:
559         case AL_SOURCE_TYPE:
560         case AL_DISTANCE_MODEL:
561         case AL_DIRECT_FILTER_GAINHF_AUTO:
562         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
563         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
564         case AL_DIRECT_CHANNELS_SOFT:
565             ival = (ALint)values[0];
566             return SetSourceiv(Source, Context, prop, &ival);
567
568         case AL_BUFFERS_QUEUED:
569         case AL_BUFFERS_PROCESSED:
570             ival = (ALint)((ALuint)values[0]);
571             return SetSourceiv(Source, Context, prop, &ival);
572
573         case AL_BUFFER:
574         case AL_DIRECT_FILTER:
575         case AL_AUXILIARY_SEND_FILTER:
576         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
577             break;
578     }
579
580     ERR("Unexpected property: 0x%04x\n", prop);
581     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
582 }
583
584 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
585 {
586     ALCdevice *device = Context->Device;
587     ALbuffer  *buffer = NULL;
588     ALfilter  *filter = NULL;
589     ALeffectslot *slot = NULL;
590     ALbufferlistitem *oldlist;
591     ALbufferlistitem *newlist;
592     ALfloat fvals[6];
593
594     switch(prop)
595     {
596         case AL_SOURCE_STATE:
597         case AL_SOURCE_TYPE:
598         case AL_BUFFERS_QUEUED:
599         case AL_BUFFERS_PROCESSED:
600         case AL_SAMPLE_RW_OFFSETS_SOFT:
601         case AL_BYTE_RW_OFFSETS_SOFT:
602         case AL_BYTE_LENGTH_SOFT:
603         case AL_SAMPLE_LENGTH_SOFT:
604         case AL_SEC_LENGTH_SOFT:
605             /* Query only */
606             SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
607
608         case AL_SOURCE_RELATIVE:
609             CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
610
611             Source->HeadRelative = (ALboolean)*values;
612             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
613             return AL_TRUE;
614
615         case AL_LOOPING:
616             CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
617
618             Source->Looping = (ALboolean)*values;
619             return AL_TRUE;
620
621 #ifdef __TIZEN__
622         case AL_LOOP_COUNT:
623         {
624             ALuint uValue = (ALuint)(*values);
625             if(uValue > 0)
626             {
627                 Source->LoopCount = uValue;
628                 Source->Looping = AL_FALSE;
629             }
630             else if(uValue == 0)
631             {
632                 Source->LoopCount = uValue;
633                 Source->Looping = AL_TRUE;
634             }
635             return AL_TRUE;
636                 }
637 #endif
638
639         case AL_BUFFER:
640             CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
641
642             WriteLock(&Source->queue_lock);
643             if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
644             {
645                 WriteUnlock(&Source->queue_lock);
646                 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
647             }
648
649             if(buffer != NULL)
650             {
651                 /* Add the selected buffer to a one-item queue */
652                 newlist = malloc(sizeof(ALbufferlistitem));
653                 newlist->buffer = buffer;
654                 newlist->next = NULL;
655                 newlist->prev = NULL;
656                 IncrementRef(&buffer->ref);
657
658                 /* Source is now Static */
659                 Source->SourceType = AL_STATIC;
660
661                 ReadLock(&buffer->lock);
662                 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
663                 Source->SampleSize  = BytesFromFmt(buffer->FmtType);
664                 ReadUnlock(&buffer->lock);
665             }
666             else
667             {
668                 /* Source is now Undetermined */
669                 Source->SourceType = AL_UNDETERMINED;
670                 newlist = NULL;
671             }
672             oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
673             ATOMIC_STORE(&Source->current_buffer, newlist);
674             WriteUnlock(&Source->queue_lock);
675
676             /* Delete all elements in the previous queue */
677             while(oldlist != NULL)
678             {
679                 ALbufferlistitem *temp = oldlist;
680                 oldlist = temp->next;
681
682                 if(temp->buffer)
683                     DecrementRef(&temp->buffer->ref);
684                 free(temp);
685             }
686             return AL_TRUE;
687
688         case AL_SEC_OFFSET:
689         case AL_SAMPLE_OFFSET:
690         case AL_BYTE_OFFSET:
691             CHECKVAL(*values >= 0);
692
693             LockContext(Context);
694             Source->OffsetType = prop;
695             Source->Offset = *values;
696
697             if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
698                 !Context->DeferUpdates)
699             {
700                 WriteLock(&Source->queue_lock);
701                 if(ApplyOffset(Source) == AL_FALSE)
702                 {
703                     WriteUnlock(&Source->queue_lock);
704                     UnlockContext(Context);
705                     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
706                 }
707                 WriteUnlock(&Source->queue_lock);
708             }
709             UnlockContext(Context);
710             return AL_TRUE;
711
712         case AL_DIRECT_FILTER:
713             CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
714
715             LockContext(Context);
716             if(!filter)
717             {
718                 Source->Direct.Gain = 1.0f;
719                 Source->Direct.GainHF = 1.0f;
720                 Source->Direct.HFReference = LOWPASSFREQREF;
721                 Source->Direct.GainLF = 1.0f;
722                 Source->Direct.LFReference = HIGHPASSFREQREF;
723             }
724             else
725             {
726                 Source->Direct.Gain = filter->Gain;
727                 Source->Direct.GainHF = filter->GainHF;
728                 Source->Direct.HFReference = filter->HFReference;
729                 Source->Direct.GainLF = filter->GainLF;
730                 Source->Direct.LFReference = filter->LFReference;
731             }
732             UnlockContext(Context);
733             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
734             return AL_TRUE;
735
736         case AL_DIRECT_FILTER_GAINHF_AUTO:
737             CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
738
739             Source->DryGainHFAuto = *values;
740             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
741             return AL_TRUE;
742
743         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
744             CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
745
746             Source->WetGainAuto = *values;
747             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
748             return AL_TRUE;
749
750         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
751             CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
752
753             Source->WetGainHFAuto = *values;
754             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
755             return AL_TRUE;
756
757         case AL_DIRECT_CHANNELS_SOFT:
758             CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
759
760             Source->DirectChannels = *values;
761             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
762             return AL_TRUE;
763
764         case AL_DISTANCE_MODEL:
765             CHECKVAL(*values == AL_NONE ||
766                      *values == AL_INVERSE_DISTANCE ||
767                      *values == AL_INVERSE_DISTANCE_CLAMPED ||
768                      *values == AL_LINEAR_DISTANCE ||
769                      *values == AL_LINEAR_DISTANCE_CLAMPED ||
770                      *values == AL_EXPONENT_DISTANCE ||
771                      *values == AL_EXPONENT_DISTANCE_CLAMPED);
772
773             Source->DistanceModel = *values;
774             if(Context->SourceDistanceModel)
775                 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
776             return AL_TRUE;
777
778
779         case AL_AUXILIARY_SEND_FILTER:
780             LockContext(Context);
781             if(!((ALuint)values[1] < device->NumAuxSends &&
782                  (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
783                  (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
784             {
785                 UnlockContext(Context);
786                 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
787             }
788
789             /* Add refcount on the new slot, and release the previous slot */
790             if(slot) IncrementRef(&slot->ref);
791             slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
792             if(slot) DecrementRef(&slot->ref);
793
794             if(!filter)
795             {
796                 /* Disable filter */
797                 Source->Send[values[1]].Gain = 1.0f;
798                 Source->Send[values[1]].GainHF = 1.0f;
799                 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
800                 Source->Send[values[1]].GainLF = 1.0f;
801                 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
802             }
803             else
804             {
805                 Source->Send[values[1]].Gain = filter->Gain;
806                 Source->Send[values[1]].GainHF = filter->GainHF;
807                 Source->Send[values[1]].HFReference = filter->HFReference;
808                 Source->Send[values[1]].GainLF = filter->GainLF;
809                 Source->Send[values[1]].LFReference = filter->LFReference;
810             }
811             UnlockContext(Context);
812             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
813             return AL_TRUE;
814
815
816         /* 1x float */
817         case AL_CONE_INNER_ANGLE:
818         case AL_CONE_OUTER_ANGLE:
819         case AL_PITCH:
820         case AL_GAIN:
821         case AL_MIN_GAIN:
822         case AL_MAX_GAIN:
823         case AL_REFERENCE_DISTANCE:
824         case AL_ROLLOFF_FACTOR:
825         case AL_CONE_OUTER_GAIN:
826         case AL_MAX_DISTANCE:
827         case AL_DOPPLER_FACTOR:
828         case AL_CONE_OUTER_GAINHF:
829         case AL_AIR_ABSORPTION_FACTOR:
830         case AL_ROOM_ROLLOFF_FACTOR:
831             fvals[0] = (ALfloat)*values;
832             return SetSourcefv(Source, Context, (int)prop, fvals);
833
834         /* 3x float */
835         case AL_POSITION:
836         case AL_VELOCITY:
837         case AL_DIRECTION:
838             fvals[0] = (ALfloat)values[0];
839             fvals[1] = (ALfloat)values[1];
840             fvals[2] = (ALfloat)values[2];
841             return SetSourcefv(Source, Context, (int)prop, fvals);
842
843         /* 6x float */
844         case AL_ORIENTATION:
845             fvals[0] = (ALfloat)values[0];
846             fvals[1] = (ALfloat)values[1];
847             fvals[2] = (ALfloat)values[2];
848             fvals[3] = (ALfloat)values[3];
849             fvals[4] = (ALfloat)values[4];
850             fvals[5] = (ALfloat)values[5];
851             return SetSourcefv(Source, Context, (int)prop, fvals);
852
853         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
854         case AL_SEC_OFFSET_LATENCY_SOFT:
855             break;
856     }
857
858     ERR("Unexpected property: 0x%04x\n", prop);
859     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
860 }
861
862 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
863 {
864     ALfloat fvals[6];
865     ALint   ivals[3];
866
867     switch(prop)
868     {
869         case AL_SOURCE_TYPE:
870         case AL_BUFFERS_QUEUED:
871         case AL_BUFFERS_PROCESSED:
872         case AL_SOURCE_STATE:
873         case AL_SAMPLE_RW_OFFSETS_SOFT:
874         case AL_BYTE_RW_OFFSETS_SOFT:
875         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
876         case AL_BYTE_LENGTH_SOFT:
877         case AL_SAMPLE_LENGTH_SOFT:
878         case AL_SEC_LENGTH_SOFT:
879             /* Query only */
880             SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
881
882
883         /* 1x int */
884         case AL_SOURCE_RELATIVE:
885         case AL_LOOPING:
886         case AL_SEC_OFFSET:
887         case AL_SAMPLE_OFFSET:
888         case AL_BYTE_OFFSET:
889         case AL_DIRECT_FILTER_GAINHF_AUTO:
890         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
891         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
892         case AL_DIRECT_CHANNELS_SOFT:
893         case AL_DISTANCE_MODEL:
894             CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
895
896             ivals[0] = (ALint)*values;
897             return SetSourceiv(Source, Context, (int)prop, ivals);
898
899         /* 1x uint */
900         case AL_BUFFER:
901         case AL_DIRECT_FILTER:
902             CHECKVAL(*values <= UINT_MAX && *values >= 0);
903
904             ivals[0] = (ALuint)*values;
905             return SetSourceiv(Source, Context, (int)prop, ivals);
906
907         /* 3x uint */
908         case AL_AUXILIARY_SEND_FILTER:
909             CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
910                      values[1] <= UINT_MAX && values[1] >= 0 &&
911                      values[2] <= UINT_MAX && values[2] >= 0);
912
913             ivals[0] = (ALuint)values[0];
914             ivals[1] = (ALuint)values[1];
915             ivals[2] = (ALuint)values[2];
916             return SetSourceiv(Source, Context, (int)prop, ivals);
917
918         /* 1x float */
919         case AL_CONE_INNER_ANGLE:
920         case AL_CONE_OUTER_ANGLE:
921         case AL_PITCH:
922         case AL_GAIN:
923         case AL_MIN_GAIN:
924         case AL_MAX_GAIN:
925         case AL_REFERENCE_DISTANCE:
926         case AL_ROLLOFF_FACTOR:
927         case AL_CONE_OUTER_GAIN:
928         case AL_MAX_DISTANCE:
929         case AL_DOPPLER_FACTOR:
930         case AL_CONE_OUTER_GAINHF:
931         case AL_AIR_ABSORPTION_FACTOR:
932         case AL_ROOM_ROLLOFF_FACTOR:
933             fvals[0] = (ALfloat)*values;
934             return SetSourcefv(Source, Context, (int)prop, fvals);
935
936         /* 3x float */
937         case AL_POSITION:
938         case AL_VELOCITY:
939         case AL_DIRECTION:
940             fvals[0] = (ALfloat)values[0];
941             fvals[1] = (ALfloat)values[1];
942             fvals[2] = (ALfloat)values[2];
943             return SetSourcefv(Source, Context, (int)prop, fvals);
944
945         /* 6x float */
946         case AL_ORIENTATION:
947             fvals[0] = (ALfloat)values[0];
948             fvals[1] = (ALfloat)values[1];
949             fvals[2] = (ALfloat)values[2];
950             fvals[3] = (ALfloat)values[3];
951             fvals[4] = (ALfloat)values[4];
952             fvals[5] = (ALfloat)values[5];
953             return SetSourcefv(Source, Context, (int)prop, fvals);
954
955         case AL_SEC_OFFSET_LATENCY_SOFT:
956             break;
957     }
958
959     ERR("Unexpected property: 0x%04x\n", prop);
960     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
961 }
962
963 #undef CHECKVAL
964
965
966 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
967 {
968     ALCdevice *device = Context->Device;
969     ALbufferlistitem *BufferList;
970     ALdouble offsets[2];
971     ALdouble updateLen;
972     ALint ivals[3];
973     ALboolean err;
974
975     switch(prop)
976     {
977         case AL_GAIN:
978             *values = Source->Gain;
979             return AL_TRUE;
980
981         case AL_PITCH:
982             *values = Source->Pitch;
983             return AL_TRUE;
984
985         case AL_MAX_DISTANCE:
986             *values = Source->MaxDistance;
987             return AL_TRUE;
988
989         case AL_ROLLOFF_FACTOR:
990             *values = Source->RollOffFactor;
991             return AL_TRUE;
992
993         case AL_REFERENCE_DISTANCE:
994             *values = Source->RefDistance;
995             return AL_TRUE;
996
997         case AL_CONE_INNER_ANGLE:
998             *values = Source->InnerAngle;
999             return AL_TRUE;
1000
1001         case AL_CONE_OUTER_ANGLE:
1002             *values = Source->OuterAngle;
1003             return AL_TRUE;
1004
1005         case AL_MIN_GAIN:
1006             *values = Source->MinGain;
1007             return AL_TRUE;
1008
1009         case AL_MAX_GAIN:
1010             *values = Source->MaxGain;
1011             return AL_TRUE;
1012
1013         case AL_CONE_OUTER_GAIN:
1014             *values = Source->OuterGain;
1015             return AL_TRUE;
1016
1017         case AL_SEC_OFFSET:
1018         case AL_SAMPLE_OFFSET:
1019         case AL_BYTE_OFFSET:
1020             LockContext(Context);
1021             GetSourceOffsets(Source, prop, offsets, 0.0);
1022             UnlockContext(Context);
1023             *values = offsets[0];
1024             return AL_TRUE;
1025
1026         case AL_CONE_OUTER_GAINHF:
1027             *values = Source->OuterGainHF;
1028             return AL_TRUE;
1029
1030         case AL_AIR_ABSORPTION_FACTOR:
1031             *values = Source->AirAbsorptionFactor;
1032             return AL_TRUE;
1033
1034         case AL_ROOM_ROLLOFF_FACTOR:
1035             *values = Source->RoomRolloffFactor;
1036             return AL_TRUE;
1037
1038         case AL_DOPPLER_FACTOR:
1039             *values = Source->DopplerFactor;
1040             return AL_TRUE;
1041
1042         case AL_SEC_LENGTH_SOFT:
1043             ReadLock(&Source->queue_lock);
1044             if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1045                 *values = 0;
1046             else
1047             {
1048                 ALint length = 0;
1049                 ALsizei freq = 1;
1050                 do {
1051                     ALbuffer *buffer = BufferList->buffer;
1052                     if(buffer && buffer->SampleLen > 0)
1053                     {
1054                         freq = buffer->Frequency;
1055                         length += buffer->SampleLen;
1056                     }
1057                 } while((BufferList=BufferList->next) != NULL);
1058                 *values = (ALdouble)length / (ALdouble)freq;
1059             }
1060             ReadUnlock(&Source->queue_lock);
1061             return AL_TRUE;
1062
1063         case AL_SAMPLE_RW_OFFSETS_SOFT:
1064         case AL_BYTE_RW_OFFSETS_SOFT:
1065             LockContext(Context);
1066             updateLen = (ALdouble)device->UpdateSize / device->Frequency;
1067             GetSourceOffsets(Source, prop, values, updateLen);
1068             UnlockContext(Context);
1069             return AL_TRUE;
1070
1071         case AL_SEC_OFFSET_LATENCY_SOFT:
1072             LockContext(Context);
1073             values[0] = GetSourceSecOffset(Source);
1074             values[1] = (ALdouble)(V0(device->Backend,getLatency)()) /
1075                         1000000000.0;
1076             UnlockContext(Context);
1077             return AL_TRUE;
1078
1079         case AL_POSITION:
1080             LockContext(Context);
1081             values[0] = Source->Position.v[0];
1082             values[1] = Source->Position.v[1];
1083             values[2] = Source->Position.v[2];
1084             UnlockContext(Context);
1085             return AL_TRUE;
1086
1087         case AL_VELOCITY:
1088             LockContext(Context);
1089             values[0] = Source->Velocity.v[0];
1090             values[1] = Source->Velocity.v[1];
1091             values[2] = Source->Velocity.v[2];
1092             UnlockContext(Context);
1093             return AL_TRUE;
1094
1095         case AL_DIRECTION:
1096             LockContext(Context);
1097             values[0] = Source->Direction.v[0];
1098             values[1] = Source->Direction.v[1];
1099             values[2] = Source->Direction.v[2];
1100             UnlockContext(Context);
1101             return AL_TRUE;
1102
1103         case AL_ORIENTATION:
1104             LockContext(Context);
1105             values[0] = Source->Orientation[0][0];
1106             values[1] = Source->Orientation[0][1];
1107             values[2] = Source->Orientation[0][2];
1108             values[3] = Source->Orientation[1][0];
1109             values[4] = Source->Orientation[1][1];
1110             values[5] = Source->Orientation[1][2];
1111             UnlockContext(Context);
1112             return AL_TRUE;
1113
1114         /* 1x int */
1115         case AL_SOURCE_RELATIVE:
1116         case AL_LOOPING:
1117         case AL_SOURCE_STATE:
1118         case AL_BUFFERS_QUEUED:
1119         case AL_BUFFERS_PROCESSED:
1120         case AL_SOURCE_TYPE:
1121         case AL_DIRECT_FILTER_GAINHF_AUTO:
1122         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1123         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1124         case AL_DIRECT_CHANNELS_SOFT:
1125         case AL_BYTE_LENGTH_SOFT:
1126         case AL_SAMPLE_LENGTH_SOFT:
1127         case AL_DISTANCE_MODEL:
1128             if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1129                 *values = (ALdouble)ivals[0];
1130             return err;
1131
1132         case AL_BUFFER:
1133         case AL_DIRECT_FILTER:
1134         case AL_AUXILIARY_SEND_FILTER:
1135         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1136             break;
1137     }
1138
1139     ERR("Unexpected property: 0x%04x\n", prop);
1140     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1141 }
1142
1143 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1144 {
1145     ALbufferlistitem *BufferList;
1146     ALdouble dvals[6];
1147     ALboolean err;
1148
1149     switch(prop)
1150     {
1151         case AL_SOURCE_RELATIVE:
1152             *values = Source->HeadRelative;
1153             return AL_TRUE;
1154
1155         case AL_LOOPING:
1156             *values = Source->Looping;
1157             return AL_TRUE;
1158
1159         case AL_BUFFER:
1160             ReadLock(&Source->queue_lock);
1161             BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1162                                                              ATOMIC_LOAD(&Source->current_buffer);
1163             *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1164             ReadUnlock(&Source->queue_lock);
1165             return AL_TRUE;
1166
1167         case AL_SOURCE_STATE:
1168             *values = Source->state;
1169             return AL_TRUE;
1170
1171         case AL_BYTE_LENGTH_SOFT:
1172             ReadLock(&Source->queue_lock);
1173             if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1174                 *values = 0;
1175             else
1176             {
1177                 ALint length = 0;
1178                 do {
1179                     ALbuffer *buffer = BufferList->buffer;
1180                     if(buffer && buffer->SampleLen > 0)
1181                     {
1182                         ALuint byte_align, sample_align;
1183                         if(buffer->OriginalType == UserFmtIMA4)
1184                         {
1185                             ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1186                             byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1187                             sample_align = buffer->OriginalAlign;
1188                         }
1189                         else if(buffer->OriginalType == UserFmtMSADPCM)
1190                         {
1191                             ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1192                             byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1193                             sample_align = buffer->OriginalAlign;
1194                         }
1195                         else
1196                         {
1197                             ALsizei align = buffer->OriginalAlign;
1198                             byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1199                             sample_align = buffer->OriginalAlign;
1200                         }
1201
1202                         length += buffer->SampleLen / sample_align * byte_align;
1203                     }
1204                 } while((BufferList=BufferList->next) != NULL);
1205                 *values = length;
1206             }
1207             ReadUnlock(&Source->queue_lock);
1208             return AL_TRUE;
1209
1210         case AL_SAMPLE_LENGTH_SOFT:
1211             ReadLock(&Source->queue_lock);
1212             if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1213                 *values = 0;
1214             else
1215             {
1216                 ALint length = 0;
1217                 do {
1218                     ALbuffer *buffer = BufferList->buffer;
1219                     if(buffer) length += buffer->SampleLen;
1220                 } while((BufferList=BufferList->next) != NULL);
1221                 *values = length;
1222             }
1223             ReadUnlock(&Source->queue_lock);
1224             return AL_TRUE;
1225
1226         case AL_BUFFERS_QUEUED:
1227             ReadLock(&Source->queue_lock);
1228             if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1229                 *values = 0;
1230             else
1231             {
1232                 ALsizei count = 0;
1233                 do {
1234                     ++count;
1235                 } while((BufferList=BufferList->next) != NULL);
1236                 *values = count;
1237             }
1238             ReadUnlock(&Source->queue_lock);
1239             return AL_TRUE;
1240
1241         case AL_BUFFERS_PROCESSED:
1242             ReadLock(&Source->queue_lock);
1243             if(Source->Looping || Source->SourceType != AL_STREAMING)
1244             {
1245                 /* Buffers on a looping source are in a perpetual state of
1246                  * PENDING, so don't report any as PROCESSED */
1247                 *values = 0;
1248             }
1249             else
1250             {
1251                 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1252                 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1253                 ALsizei played = 0;
1254                 while(BufferList && BufferList != Current)
1255                 {
1256                     played++;
1257                     BufferList = BufferList->next;
1258                 }
1259                 *values = played;
1260             }
1261             ReadUnlock(&Source->queue_lock);
1262             return AL_TRUE;
1263
1264         case AL_SOURCE_TYPE:
1265             *values = Source->SourceType;
1266             return AL_TRUE;
1267
1268         case AL_DIRECT_FILTER_GAINHF_AUTO:
1269             *values = Source->DryGainHFAuto;
1270             return AL_TRUE;
1271
1272         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1273             *values = Source->WetGainAuto;
1274             return AL_TRUE;
1275
1276         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1277             *values = Source->WetGainHFAuto;
1278             return AL_TRUE;
1279
1280         case AL_DIRECT_CHANNELS_SOFT:
1281             *values = Source->DirectChannels;
1282             return AL_TRUE;
1283
1284         case AL_DISTANCE_MODEL:
1285             *values = Source->DistanceModel;
1286             return AL_TRUE;
1287
1288         /* 1x float/double */
1289         case AL_CONE_INNER_ANGLE:
1290         case AL_CONE_OUTER_ANGLE:
1291         case AL_PITCH:
1292         case AL_GAIN:
1293         case AL_MIN_GAIN:
1294         case AL_MAX_GAIN:
1295         case AL_REFERENCE_DISTANCE:
1296         case AL_ROLLOFF_FACTOR:
1297         case AL_CONE_OUTER_GAIN:
1298         case AL_MAX_DISTANCE:
1299         case AL_SEC_OFFSET:
1300         case AL_SAMPLE_OFFSET:
1301         case AL_BYTE_OFFSET:
1302         case AL_DOPPLER_FACTOR:
1303         case AL_AIR_ABSORPTION_FACTOR:
1304         case AL_ROOM_ROLLOFF_FACTOR:
1305         case AL_CONE_OUTER_GAINHF:
1306         case AL_SEC_LENGTH_SOFT:
1307             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1308                 *values = (ALint)dvals[0];
1309             return err;
1310
1311         /* 2x float/double */
1312         case AL_SAMPLE_RW_OFFSETS_SOFT:
1313         case AL_BYTE_RW_OFFSETS_SOFT:
1314             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1315             {
1316                 values[0] = (ALint)dvals[0];
1317                 values[1] = (ALint)dvals[1];
1318             }
1319             return err;
1320
1321         /* 3x float/double */
1322         case AL_POSITION:
1323         case AL_VELOCITY:
1324         case AL_DIRECTION:
1325             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1326             {
1327                 values[0] = (ALint)dvals[0];
1328                 values[1] = (ALint)dvals[1];
1329                 values[2] = (ALint)dvals[2];
1330             }
1331             return err;
1332
1333         /* 6x float/double */
1334         case AL_ORIENTATION:
1335             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1336             {
1337                 values[0] = (ALint)dvals[0];
1338                 values[1] = (ALint)dvals[1];
1339                 values[2] = (ALint)dvals[2];
1340                 values[3] = (ALint)dvals[3];
1341                 values[4] = (ALint)dvals[4];
1342                 values[5] = (ALint)dvals[5];
1343             }
1344             return err;
1345
1346         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1347             break; /* i64 only */
1348         case AL_SEC_OFFSET_LATENCY_SOFT:
1349             break; /* Double only */
1350
1351         case AL_DIRECT_FILTER:
1352         case AL_AUXILIARY_SEND_FILTER:
1353             break; /* ??? */
1354     }
1355
1356     ERR("Unexpected property: 0x%04x\n", prop);
1357     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1358 }
1359
1360 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1361 {
1362     ALCdevice *device = Context->Device;
1363     ALdouble dvals[6];
1364     ALint ivals[3];
1365     ALboolean err;
1366
1367     switch(prop)
1368     {
1369         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1370             LockContext(Context);
1371             values[0] = GetSourceSampleOffset(Source);
1372             values[1] = V0(device->Backend,getLatency)();
1373             UnlockContext(Context);
1374             return AL_TRUE;
1375
1376         /* 1x float/double */
1377         case AL_CONE_INNER_ANGLE:
1378         case AL_CONE_OUTER_ANGLE:
1379         case AL_PITCH:
1380         case AL_GAIN:
1381         case AL_MIN_GAIN:
1382         case AL_MAX_GAIN:
1383         case AL_REFERENCE_DISTANCE:
1384         case AL_ROLLOFF_FACTOR:
1385         case AL_CONE_OUTER_GAIN:
1386         case AL_MAX_DISTANCE:
1387         case AL_SEC_OFFSET:
1388         case AL_SAMPLE_OFFSET:
1389         case AL_BYTE_OFFSET:
1390         case AL_DOPPLER_FACTOR:
1391         case AL_AIR_ABSORPTION_FACTOR:
1392         case AL_ROOM_ROLLOFF_FACTOR:
1393         case AL_CONE_OUTER_GAINHF:
1394         case AL_SEC_LENGTH_SOFT:
1395             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1396                 *values = (ALint64)dvals[0];
1397             return err;
1398
1399         /* 2x float/double */
1400         case AL_SAMPLE_RW_OFFSETS_SOFT:
1401         case AL_BYTE_RW_OFFSETS_SOFT:
1402             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1403             {
1404                 values[0] = (ALint64)dvals[0];
1405                 values[1] = (ALint64)dvals[1];
1406             }
1407             return err;
1408
1409         /* 3x float/double */
1410         case AL_POSITION:
1411         case AL_VELOCITY:
1412         case AL_DIRECTION:
1413             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1414             {
1415                 values[0] = (ALint64)dvals[0];
1416                 values[1] = (ALint64)dvals[1];
1417                 values[2] = (ALint64)dvals[2];
1418             }
1419             return err;
1420
1421         /* 6x float/double */
1422         case AL_ORIENTATION:
1423             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1424             {
1425                 values[0] = (ALint64)dvals[0];
1426                 values[1] = (ALint64)dvals[1];
1427                 values[2] = (ALint64)dvals[2];
1428                 values[3] = (ALint64)dvals[3];
1429                 values[4] = (ALint64)dvals[4];
1430                 values[5] = (ALint64)dvals[5];
1431             }
1432             return err;
1433
1434         /* 1x int */
1435         case AL_SOURCE_RELATIVE:
1436         case AL_LOOPING:
1437         case AL_SOURCE_STATE:
1438         case AL_BUFFERS_QUEUED:
1439         case AL_BUFFERS_PROCESSED:
1440         case AL_BYTE_LENGTH_SOFT:
1441         case AL_SAMPLE_LENGTH_SOFT:
1442         case AL_SOURCE_TYPE:
1443         case AL_DIRECT_FILTER_GAINHF_AUTO:
1444         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1445         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1446         case AL_DIRECT_CHANNELS_SOFT:
1447         case AL_DISTANCE_MODEL:
1448             if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1449                 *values = ivals[0];
1450             return err;
1451
1452         /* 1x uint */
1453         case AL_BUFFER:
1454         case AL_DIRECT_FILTER:
1455             if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1456                 *values = (ALuint)ivals[0];
1457             return err;
1458
1459         /* 3x uint */
1460         case AL_AUXILIARY_SEND_FILTER:
1461             if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1462             {
1463                 values[0] = (ALuint)ivals[0];
1464                 values[1] = (ALuint)ivals[1];
1465                 values[2] = (ALuint)ivals[2];
1466             }
1467             return err;
1468
1469         case AL_SEC_OFFSET_LATENCY_SOFT:
1470             break; /* Double only */
1471     }
1472
1473     ERR("Unexpected property: 0x%04x\n", prop);
1474     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1475 }
1476
1477
1478 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1479 {
1480     ALCcontext *context;
1481     ALsizei cur = 0;
1482     ALenum err;
1483
1484     context = GetContextRef();
1485     if(!context) return;
1486
1487     if(!(n >= 0))
1488         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1489     for(cur = 0;cur < n;cur++)
1490     {
1491         ALsource *source = al_calloc(16, sizeof(ALsource));
1492         if(!source)
1493         {
1494             alDeleteSources(cur, sources);
1495             SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1496         }
1497         InitSourceParams(source);
1498
1499         err = NewThunkEntry(&source->id);
1500         if(err == AL_NO_ERROR)
1501             err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1502         if(err != AL_NO_ERROR)
1503         {
1504             FreeThunkEntry(source->id);
1505             memset(source, 0, sizeof(ALsource));
1506             al_free(source);
1507
1508             alDeleteSources(cur, sources);
1509             SET_ERROR_AND_GOTO(context, err, done);
1510         }
1511
1512         sources[cur] = source->id;
1513     }
1514
1515 done:
1516     ALCcontext_DecRef(context);
1517 }
1518
1519
1520 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1521 {
1522     ALCcontext *context;
1523     ALbufferlistitem *BufferList;
1524     ALsource *Source;
1525     ALsizei i, j;
1526
1527     context = GetContextRef();
1528     if(!context) return;
1529
1530     if(!(n >= 0))
1531         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1532
1533     /* Check that all Sources are valid */
1534     for(i = 0;i < n;i++)
1535     {
1536         if(LookupSource(context, sources[i]) == NULL)
1537             SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1538     }
1539     for(i = 0;i < n;i++)
1540     {
1541         ALvoice *voice, *voice_end;
1542
1543         if((Source=RemoveSource(context, sources[i])) == NULL)
1544             continue;
1545         FreeThunkEntry(Source->id);
1546
1547         LockContext(context);
1548         voice = context->Voices;
1549         voice_end = voice + context->VoiceCount;
1550         while(voice != voice_end)
1551         {
1552             ALsource *old = Source;
1553             if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1554                 break;
1555             voice++;
1556         }
1557         UnlockContext(context);
1558
1559         BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
1560         while(BufferList != NULL)
1561         {
1562             ALbufferlistitem *next = BufferList->next;
1563             if(BufferList->buffer != NULL)
1564                 DecrementRef(&BufferList->buffer->ref);
1565             free(BufferList);
1566             BufferList = next;
1567         }
1568
1569         for(j = 0;j < MAX_SENDS;++j)
1570         {
1571             if(Source->Send[j].Slot)
1572                 DecrementRef(&Source->Send[j].Slot->ref);
1573             Source->Send[j].Slot = NULL;
1574         }
1575
1576         memset(Source, 0, sizeof(*Source));
1577         al_free(Source);
1578     }
1579
1580 done:
1581     ALCcontext_DecRef(context);
1582 }
1583
1584
1585 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1586 {
1587     ALCcontext *context;
1588     ALboolean ret;
1589
1590     context = GetContextRef();
1591     if(!context) return AL_FALSE;
1592
1593     ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1594
1595     ALCcontext_DecRef(context);
1596
1597     return ret;
1598 }
1599
1600
1601 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1602 {
1603     ALCcontext *Context;
1604     ALsource   *Source;
1605
1606     Context = GetContextRef();
1607     if(!Context) return;
1608
1609     if((Source=LookupSource(Context, source)) == NULL)
1610         alSetError(Context, AL_INVALID_NAME);
1611     else if(!(FloatValsByProp(param) == 1))
1612         alSetError(Context, AL_INVALID_ENUM);
1613     else
1614         SetSourcefv(Source, Context, param, &value);
1615
1616     ALCcontext_DecRef(Context);
1617 }
1618
1619 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1620 {
1621     ALCcontext *Context;
1622     ALsource   *Source;
1623
1624     Context = GetContextRef();
1625     if(!Context) return;
1626
1627     if((Source=LookupSource(Context, source)) == NULL)
1628         alSetError(Context, AL_INVALID_NAME);
1629     else if(!(FloatValsByProp(param) == 3))
1630         alSetError(Context, AL_INVALID_ENUM);
1631     else
1632     {
1633         ALfloat fvals[3] = { value1, value2, value3 };
1634         SetSourcefv(Source, Context, param, fvals);
1635     }
1636
1637     ALCcontext_DecRef(Context);
1638 }
1639
1640 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1641 {
1642     ALCcontext *Context;
1643     ALsource   *Source;
1644
1645     Context = GetContextRef();
1646     if(!Context) return;
1647
1648     if((Source=LookupSource(Context, source)) == NULL)
1649         alSetError(Context, AL_INVALID_NAME);
1650     else if(!values)
1651         alSetError(Context, AL_INVALID_VALUE);
1652     else if(!(FloatValsByProp(param) > 0))
1653         alSetError(Context, AL_INVALID_ENUM);
1654     else
1655         SetSourcefv(Source, Context, param, values);
1656
1657     ALCcontext_DecRef(Context);
1658 }
1659
1660
1661 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1662 {
1663     ALCcontext *Context;
1664     ALsource   *Source;
1665
1666     Context = GetContextRef();
1667     if(!Context) return;
1668
1669     if((Source=LookupSource(Context, source)) == NULL)
1670         alSetError(Context, AL_INVALID_NAME);
1671     else if(!(DoubleValsByProp(param) == 1))
1672         alSetError(Context, AL_INVALID_ENUM);
1673     else
1674     {
1675         ALfloat fval = (ALfloat)value;
1676         SetSourcefv(Source, Context, param, &fval);
1677     }
1678
1679     ALCcontext_DecRef(Context);
1680 }
1681
1682 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1683 {
1684     ALCcontext *Context;
1685     ALsource   *Source;
1686
1687     Context = GetContextRef();
1688     if(!Context) return;
1689
1690     if((Source=LookupSource(Context, source)) == NULL)
1691         alSetError(Context, AL_INVALID_NAME);
1692     else if(!(DoubleValsByProp(param) == 3))
1693         alSetError(Context, AL_INVALID_ENUM);
1694     else
1695     {
1696         ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1697         SetSourcefv(Source, Context, param, fvals);
1698     }
1699
1700     ALCcontext_DecRef(Context);
1701 }
1702
1703 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1704 {
1705     ALCcontext *Context;
1706     ALsource   *Source;
1707     ALint      count;
1708
1709     Context = GetContextRef();
1710     if(!Context) return;
1711
1712     if((Source=LookupSource(Context, source)) == NULL)
1713         alSetError(Context, AL_INVALID_NAME);
1714     else if(!values)
1715         alSetError(Context, AL_INVALID_VALUE);
1716     else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1717         alSetError(Context, AL_INVALID_ENUM);
1718     else
1719     {
1720         ALfloat fvals[6];
1721         ALint i;
1722
1723         for(i = 0;i < count;i++)
1724             fvals[i] = (ALfloat)values[i];
1725         SetSourcefv(Source, Context, param, fvals);
1726     }
1727
1728     ALCcontext_DecRef(Context);
1729 }
1730
1731 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1732 {
1733     ALCcontext *Context;
1734     ALsource   *Source;
1735
1736     Context = GetContextRef();
1737     if(!Context) return;
1738
1739     if((Source=LookupSource(Context, source)) == NULL)
1740         alSetError(Context, AL_INVALID_NAME);
1741     else if(!(IntValsByProp(param) == 1))
1742         alSetError(Context, AL_INVALID_ENUM);
1743     else
1744         SetSourceiv(Source, Context, param, &value);
1745
1746     ALCcontext_DecRef(Context);
1747 }
1748
1749 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1750 {
1751     ALCcontext *Context;
1752     ALsource   *Source;
1753
1754     Context = GetContextRef();
1755     if(!Context) return;
1756
1757     if((Source=LookupSource(Context, source)) == NULL)
1758         alSetError(Context, AL_INVALID_NAME);
1759     else if(!(IntValsByProp(param) == 3))
1760         alSetError(Context, AL_INVALID_ENUM);
1761     else
1762     {
1763         ALint ivals[3] = { value1, value2, value3 };
1764         SetSourceiv(Source, Context, param, ivals);
1765     }
1766
1767     ALCcontext_DecRef(Context);
1768 }
1769
1770 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1771 {
1772     ALCcontext *Context;
1773     ALsource   *Source;
1774
1775     Context = GetContextRef();
1776     if(!Context) return;
1777
1778     if((Source=LookupSource(Context, source)) == NULL)
1779         alSetError(Context, AL_INVALID_NAME);
1780     else if(!values)
1781         alSetError(Context, AL_INVALID_VALUE);
1782     else if(!(IntValsByProp(param) > 0))
1783         alSetError(Context, AL_INVALID_ENUM);
1784     else
1785         SetSourceiv(Source, Context, param, values);
1786
1787     ALCcontext_DecRef(Context);
1788 }
1789
1790
1791 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1792 {
1793     ALCcontext *Context;
1794     ALsource   *Source;
1795
1796     Context = GetContextRef();
1797     if(!Context) return;
1798
1799     if((Source=LookupSource(Context, source)) == NULL)
1800         alSetError(Context, AL_INVALID_NAME);
1801     else if(!(Int64ValsByProp(param) == 1))
1802         alSetError(Context, AL_INVALID_ENUM);
1803     else
1804         SetSourcei64v(Source, Context, param, &value);
1805
1806     ALCcontext_DecRef(Context);
1807 }
1808
1809 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1810 {
1811     ALCcontext *Context;
1812     ALsource   *Source;
1813
1814     Context = GetContextRef();
1815     if(!Context) return;
1816
1817     if((Source=LookupSource(Context, source)) == NULL)
1818         alSetError(Context, AL_INVALID_NAME);
1819     else if(!(Int64ValsByProp(param) == 3))
1820         alSetError(Context, AL_INVALID_ENUM);
1821     else
1822     {
1823         ALint64SOFT i64vals[3] = { value1, value2, value3 };
1824         SetSourcei64v(Source, Context, param, i64vals);
1825     }
1826
1827     ALCcontext_DecRef(Context);
1828 }
1829
1830 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1831 {
1832     ALCcontext *Context;
1833     ALsource   *Source;
1834
1835     Context = GetContextRef();
1836     if(!Context) return;
1837
1838     if((Source=LookupSource(Context, source)) == NULL)
1839         alSetError(Context, AL_INVALID_NAME);
1840     else if(!values)
1841         alSetError(Context, AL_INVALID_VALUE);
1842     else if(!(Int64ValsByProp(param) > 0))
1843         alSetError(Context, AL_INVALID_ENUM);
1844     else
1845         SetSourcei64v(Source, Context, param, values);
1846
1847     ALCcontext_DecRef(Context);
1848 }
1849
1850
1851 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1852 {
1853     ALCcontext *Context;
1854     ALsource   *Source;
1855
1856     Context = GetContextRef();
1857     if(!Context) return;
1858
1859     if((Source=LookupSource(Context, source)) == NULL)
1860         alSetError(Context, AL_INVALID_NAME);
1861     else if(!value)
1862         alSetError(Context, AL_INVALID_VALUE);
1863     else if(!(FloatValsByProp(param) == 1))
1864         alSetError(Context, AL_INVALID_ENUM);
1865     else
1866     {
1867         ALdouble dval;
1868         if(GetSourcedv(Source, Context, param, &dval))
1869             *value = (ALfloat)dval;
1870     }
1871
1872     ALCcontext_DecRef(Context);
1873 }
1874
1875
1876 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1877 {
1878     ALCcontext *Context;
1879     ALsource   *Source;
1880
1881     Context = GetContextRef();
1882     if(!Context) return;
1883
1884     if((Source=LookupSource(Context, source)) == NULL)
1885         alSetError(Context, AL_INVALID_NAME);
1886     else if(!(value1 && value2 && value3))
1887         alSetError(Context, AL_INVALID_VALUE);
1888     else if(!(FloatValsByProp(param) == 3))
1889         alSetError(Context, AL_INVALID_ENUM);
1890     else
1891     {
1892         ALdouble dvals[3];
1893         if(GetSourcedv(Source, Context, param, dvals))
1894         {
1895             *value1 = (ALfloat)dvals[0];
1896             *value2 = (ALfloat)dvals[1];
1897             *value3 = (ALfloat)dvals[2];
1898         }
1899     }
1900
1901     ALCcontext_DecRef(Context);
1902 }
1903
1904
1905 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1906 {
1907     ALCcontext *Context;
1908     ALsource   *Source;
1909     ALint      count;
1910
1911     Context = GetContextRef();
1912     if(!Context) return;
1913
1914     if((Source=LookupSource(Context, source)) == NULL)
1915         alSetError(Context, AL_INVALID_NAME);
1916     else if(!values)
1917         alSetError(Context, AL_INVALID_VALUE);
1918     else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
1919         alSetError(Context, AL_INVALID_ENUM);
1920     else
1921     {
1922         ALdouble dvals[6];
1923         if(GetSourcedv(Source, Context, param, dvals))
1924         {
1925             ALint i;
1926             for(i = 0;i < count;i++)
1927                 values[i] = (ALfloat)dvals[i];
1928         }
1929     }
1930
1931     ALCcontext_DecRef(Context);
1932 }
1933
1934
1935 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1936 {
1937     ALCcontext *Context;
1938     ALsource   *Source;
1939
1940     Context = GetContextRef();
1941     if(!Context) return;
1942
1943     if((Source=LookupSource(Context, source)) == NULL)
1944         alSetError(Context, AL_INVALID_NAME);
1945     else if(!value)
1946         alSetError(Context, AL_INVALID_VALUE);
1947     else if(!(DoubleValsByProp(param) == 1))
1948         alSetError(Context, AL_INVALID_ENUM);
1949     else
1950         GetSourcedv(Source, Context, param, value);
1951
1952     ALCcontext_DecRef(Context);
1953 }
1954
1955 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1956 {
1957     ALCcontext *Context;
1958     ALsource   *Source;
1959
1960     Context = GetContextRef();
1961     if(!Context) return;
1962
1963     if((Source=LookupSource(Context, source)) == NULL)
1964         alSetError(Context, AL_INVALID_NAME);
1965     else if(!(value1 && value2 && value3))
1966         alSetError(Context, AL_INVALID_VALUE);
1967     else if(!(DoubleValsByProp(param) == 3))
1968         alSetError(Context, AL_INVALID_ENUM);
1969     else
1970     {
1971         ALdouble dvals[3];
1972         if(GetSourcedv(Source, Context, param, dvals))
1973         {
1974             *value1 = dvals[0];
1975             *value2 = dvals[1];
1976             *value3 = dvals[2];
1977         }
1978     }
1979
1980     ALCcontext_DecRef(Context);
1981 }
1982
1983 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1984 {
1985     ALCcontext *Context;
1986     ALsource   *Source;
1987
1988     Context = GetContextRef();
1989     if(!Context) return;
1990
1991     if((Source=LookupSource(Context, source)) == NULL)
1992         alSetError(Context, AL_INVALID_NAME);
1993     else if(!values)
1994         alSetError(Context, AL_INVALID_VALUE);
1995     else if(!(DoubleValsByProp(param) > 0))
1996         alSetError(Context, AL_INVALID_ENUM);
1997     else
1998         GetSourcedv(Source, Context, param, values);
1999
2000     ALCcontext_DecRef(Context);
2001 }
2002
2003
2004 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2005 {
2006     ALCcontext *Context;
2007     ALsource   *Source;
2008
2009     Context = GetContextRef();
2010     if(!Context) return;
2011
2012     if((Source=LookupSource(Context, source)) == NULL)
2013         alSetError(Context, AL_INVALID_NAME);
2014     else if(!value)
2015         alSetError(Context, AL_INVALID_VALUE);
2016     else if(!(IntValsByProp(param) == 1))
2017         alSetError(Context, AL_INVALID_ENUM);
2018     else
2019         GetSourceiv(Source, Context, param, value);
2020
2021     ALCcontext_DecRef(Context);
2022 }
2023
2024
2025 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2026 {
2027     ALCcontext *Context;
2028     ALsource   *Source;
2029
2030     Context = GetContextRef();
2031     if(!Context) return;
2032
2033     if((Source=LookupSource(Context, source)) == NULL)
2034         alSetError(Context, AL_INVALID_NAME);
2035     else if(!(value1 && value2 && value3))
2036         alSetError(Context, AL_INVALID_VALUE);
2037     else if(!(IntValsByProp(param) == 3))
2038         alSetError(Context, AL_INVALID_ENUM);
2039     else
2040     {
2041         ALint ivals[3];
2042         if(GetSourceiv(Source, Context, param, ivals))
2043         {
2044             *value1 = ivals[0];
2045             *value2 = ivals[1];
2046             *value3 = ivals[2];
2047         }
2048     }
2049
2050     ALCcontext_DecRef(Context);
2051 }
2052
2053
2054 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2055 {
2056     ALCcontext *Context;
2057     ALsource   *Source;
2058
2059     Context = GetContextRef();
2060     if(!Context) return;
2061
2062     if((Source=LookupSource(Context, source)) == NULL)
2063         alSetError(Context, AL_INVALID_NAME);
2064     else if(!values)
2065         alSetError(Context, AL_INVALID_VALUE);
2066     else if(!(IntValsByProp(param) > 0))
2067         alSetError(Context, AL_INVALID_ENUM);
2068     else
2069         GetSourceiv(Source, Context, param, values);
2070
2071     ALCcontext_DecRef(Context);
2072 }
2073
2074
2075 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2076 {
2077     ALCcontext *Context;
2078     ALsource   *Source;
2079
2080     Context = GetContextRef();
2081     if(!Context) return;
2082
2083     if((Source=LookupSource(Context, source)) == NULL)
2084         alSetError(Context, AL_INVALID_NAME);
2085     else if(!value)
2086         alSetError(Context, AL_INVALID_VALUE);
2087     else if(!(Int64ValsByProp(param) == 1))
2088         alSetError(Context, AL_INVALID_ENUM);
2089     else
2090         GetSourcei64v(Source, Context, param, value);
2091
2092     ALCcontext_DecRef(Context);
2093 }
2094
2095 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2096 {
2097     ALCcontext *Context;
2098     ALsource   *Source;
2099
2100     Context = GetContextRef();
2101     if(!Context) return;
2102
2103     if((Source=LookupSource(Context, source)) == NULL)
2104         alSetError(Context, AL_INVALID_NAME);
2105     else if(!(value1 && value2 && value3))
2106         alSetError(Context, AL_INVALID_VALUE);
2107     else if(!(Int64ValsByProp(param) == 3))
2108         alSetError(Context, AL_INVALID_ENUM);
2109     else
2110     {
2111         ALint64 i64vals[3];
2112         if(GetSourcei64v(Source, Context, param, i64vals))
2113         {
2114             *value1 = i64vals[0];
2115             *value2 = i64vals[1];
2116             *value3 = i64vals[2];
2117         }
2118     }
2119
2120     ALCcontext_DecRef(Context);
2121 }
2122
2123 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2124 {
2125     ALCcontext *Context;
2126     ALsource   *Source;
2127
2128     Context = GetContextRef();
2129     if(!Context) return;
2130
2131     if((Source=LookupSource(Context, source)) == NULL)
2132         alSetError(Context, AL_INVALID_NAME);
2133     else if(!values)
2134         alSetError(Context, AL_INVALID_VALUE);
2135     else if(!(Int64ValsByProp(param) > 0))
2136         alSetError(Context, AL_INVALID_ENUM);
2137     else
2138         GetSourcei64v(Source, Context, param, values);
2139
2140     ALCcontext_DecRef(Context);
2141 }
2142
2143
2144 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2145 {
2146     alSourcePlayv(1, &source);
2147 }
2148 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2149 {
2150     ALCcontext *context;
2151     ALsource *source;
2152     ALsizei i;
2153
2154     context = GetContextRef();
2155     if(!context) return;
2156
2157     if(!(n >= 0))
2158         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2159     for(i = 0;i < n;i++)
2160     {
2161         if(!LookupSource(context, sources[i]))
2162             SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2163     }
2164
2165     LockContext(context);
2166     while(n > context->MaxVoices-context->VoiceCount)
2167     {
2168         ALvoice *temp = NULL;
2169         ALsizei newcount;
2170
2171         newcount = context->MaxVoices << 1;
2172         if(newcount > 0)
2173             temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
2174         if(!temp)
2175         {
2176             UnlockContext(context);
2177             SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2178         }
2179         memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2180
2181         context->Voices = temp;
2182         context->MaxVoices = newcount;
2183     }
2184
2185     for(i = 0;i < n;i++)
2186     {
2187         source = LookupSource(context, sources[i]);
2188         if(context->DeferUpdates) source->new_state = AL_PLAYING;
2189         else SetSourceState(source, context, AL_PLAYING);
2190     }
2191
2192 #ifdef __TIZEN__
2193     /* Resume device if device is paused by alcDevicePauseSOFT() in alSourcePausev() */
2194     alcDeviceResumeSOFT(context->Device);
2195 #endif
2196
2197     UnlockContext(context);
2198
2199 done:
2200     ALCcontext_DecRef(context);
2201 }
2202
2203 #ifdef __TIZEN__
2204 static ALboolean _alPlayingSourcesExists(ALCcontext *context)
2205 {
2206     ALsource *source = NULL;
2207     ALsizei i;
2208
2209     if (context == NULL)
2210     {
2211         /* As this is error case, I think device would be safe to keep active */
2212         return AL_TRUE;
2213     }
2214
2215     for(i = 0; i < context->SourceMap.size; i++)
2216     {
2217         source = (ALsource *)context->SourceMap.array[i].value;
2218         TRACE("[total:%d, index:%d, key:%d, state:%d]\n",
2219                 context->SourceMap.size, i, source->id, source->state);
2220         if(source->state == AL_PLAYING)
2221         {
2222             TRACE(" - source[%d] is still playing....\n", source->id);
2223             return AL_TRUE;
2224         }
2225     }
2226
2227     return AL_FALSE;
2228 }
2229 #endif
2230
2231 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2232 {
2233     alSourcePausev(1, &source);
2234 }
2235 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2236 {
2237     ALCcontext *context;
2238     ALsource *source;
2239     ALsizei i;
2240
2241     context = GetContextRef();
2242     if(!context) return;
2243
2244     if(!(n >= 0))
2245         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2246     for(i = 0;i < n;i++)
2247     {
2248         if(!LookupSource(context, sources[i]))
2249             SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2250     }
2251
2252     LockContext(context);
2253     for(i = 0;i < n;i++)
2254     {
2255         source = LookupSource(context, sources[i]);
2256         if(context->DeferUpdates) source->new_state = AL_PAUSED;
2257         else SetSourceState(source, context, AL_PAUSED);
2258     }
2259     UnlockContext(context);
2260
2261 #ifdef __TIZEN__
2262     /* if there are no playing sources, pause DEVICE to let backend device can suspend
2263        device will be resumed when one of source is going to be played by alSourcePlay */
2264     if(!_alPlayingSourcesExists(context))
2265     {
2266         TRACE("No playing source in this context, do alcDevicePauseSOFT()!");
2267         alcDevicePauseSOFT(context->Device);
2268      }
2269 #endif
2270
2271 done:
2272     ALCcontext_DecRef(context);
2273 }
2274
2275 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2276 {
2277     alSourceStopv(1, &source);
2278 }
2279 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2280 {
2281     ALCcontext *context;
2282     ALsource *source;
2283     ALsizei i;
2284
2285     context = GetContextRef();
2286     if(!context) return;
2287
2288     if(!(n >= 0))
2289         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2290     for(i = 0;i < n;i++)
2291     {
2292         if(!LookupSource(context, sources[i]))
2293             SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2294     }
2295
2296     LockContext(context);
2297     for(i = 0;i < n;i++)
2298     {
2299         source = LookupSource(context, sources[i]);
2300         source->new_state = AL_NONE;
2301         SetSourceState(source, context, AL_STOPPED);
2302     }
2303     UnlockContext(context);
2304
2305 done:
2306     ALCcontext_DecRef(context);
2307 }
2308
2309 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2310 {
2311     alSourceRewindv(1, &source);
2312 }
2313 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2314 {
2315     ALCcontext *context;
2316     ALsource *source;
2317     ALsizei i;
2318
2319     context = GetContextRef();
2320     if(!context) return;
2321
2322     if(!(n >= 0))
2323         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2324     for(i = 0;i < n;i++)
2325     {
2326         if(!LookupSource(context, sources[i]))
2327             SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2328     }
2329
2330     LockContext(context);
2331     for(i = 0;i < n;i++)
2332     {
2333         source = LookupSource(context, sources[i]);
2334         source->new_state = AL_NONE;
2335         SetSourceState(source, context, AL_INITIAL);
2336     }
2337     UnlockContext(context);
2338
2339 done:
2340     ALCcontext_DecRef(context);
2341 }
2342
2343
2344 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2345 {
2346     ALCdevice *device;
2347     ALCcontext *context;
2348     ALsource *source;
2349     ALsizei i;
2350     ALbufferlistitem *BufferListStart;
2351     ALbufferlistitem *BufferList;
2352     ALbuffer *BufferFmt = NULL;
2353
2354     if(nb == 0)
2355         return;
2356
2357     context = GetContextRef();
2358     if(!context) return;
2359
2360     device = context->Device;
2361
2362     if(!(nb >= 0))
2363         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2364     if((source=LookupSource(context, src)) == NULL)
2365         SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2366
2367     WriteLock(&source->queue_lock);
2368     if(source->SourceType == AL_STATIC)
2369     {
2370         WriteUnlock(&source->queue_lock);
2371         /* Can't queue on a Static Source */
2372         SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2373     }
2374
2375     /* Check for a valid Buffer, for its frequency and format */
2376     BufferList = ATOMIC_LOAD(&source->queue);
2377     while(BufferList)
2378     {
2379         if(BufferList->buffer)
2380         {
2381             BufferFmt = BufferList->buffer;
2382             break;
2383         }
2384         BufferList = BufferList->next;
2385     }
2386
2387     BufferListStart = NULL;
2388     BufferList = NULL;
2389     for(i = 0;i < nb;i++)
2390     {
2391         ALbuffer *buffer = NULL;
2392         if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2393         {
2394             WriteUnlock(&source->queue_lock);
2395             SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2396         }
2397
2398         if(!BufferListStart)
2399         {
2400             BufferListStart = malloc(sizeof(ALbufferlistitem));
2401             BufferListStart->buffer = buffer;
2402             BufferListStart->next = NULL;
2403             BufferListStart->prev = NULL;
2404             BufferList = BufferListStart;
2405         }
2406         else
2407         {
2408             BufferList->next = malloc(sizeof(ALbufferlistitem));
2409             BufferList->next->buffer = buffer;
2410             BufferList->next->next = NULL;
2411             BufferList->next->prev = BufferList;
2412             BufferList = BufferList->next;
2413         }
2414         if(!buffer) continue;
2415
2416         /* Hold a read lock on each buffer being queued while checking all
2417          * provided buffers. This is done so other threads don't see an extra
2418          * reference on some buffers if this operation ends up failing. */
2419         ReadLock(&buffer->lock);
2420         IncrementRef(&buffer->ref);
2421
2422         if(BufferFmt == NULL)
2423         {
2424             BufferFmt = buffer;
2425
2426             source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2427             source->SampleSize  = BytesFromFmt(buffer->FmtType);
2428         }
2429         else if(BufferFmt->Frequency != buffer->Frequency ||
2430                 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2431                 BufferFmt->OriginalType != buffer->OriginalType)
2432         {
2433             WriteUnlock(&source->queue_lock);
2434             SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2435
2436         buffer_error:
2437             /* A buffer failed (invalid ID or format), so unlock and release
2438              * each buffer we had. */
2439             while(BufferList != NULL)
2440             {
2441                 ALbufferlistitem *prev = BufferList->prev;
2442                 if((buffer=BufferList->buffer) != NULL)
2443                 {
2444                     DecrementRef(&buffer->ref);
2445                     ReadUnlock(&buffer->lock);
2446                 }
2447                 free(BufferList);
2448                 BufferList = prev;
2449             }
2450             goto done;
2451         }
2452     }
2453     /* All buffers good, unlock them now. */
2454     while(BufferList != NULL)
2455     {
2456         ALbuffer *buffer = BufferList->buffer;
2457         if(buffer) ReadUnlock(&buffer->lock);
2458         BufferList = BufferList->prev;
2459     }
2460
2461     /* Source is now streaming */
2462     source->SourceType = AL_STREAMING;
2463
2464     BufferList = NULL;
2465     if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2466     {
2467         /* Queue head is not NULL, append to the end of the queue */
2468         while(BufferList->next != NULL)
2469             BufferList = BufferList->next;
2470
2471         BufferListStart->prev = BufferList;
2472         BufferList->next = BufferListStart;
2473     }
2474     BufferList = NULL;
2475     ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2476     WriteUnlock(&source->queue_lock);
2477
2478 done:
2479     ALCcontext_DecRef(context);
2480 }
2481
2482 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2483 {
2484     ALCcontext *context;
2485     ALsource *source;
2486     ALbufferlistitem *NewHead;
2487     ALbufferlistitem *OldHead;
2488     ALbufferlistitem *Current;
2489     ALsizei i;
2490
2491     if(nb == 0)
2492         return;
2493
2494     context = GetContextRef();
2495     if(!context) return;
2496
2497     if(!(nb >= 0))
2498         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2499
2500     if((source=LookupSource(context, src)) == NULL)
2501         SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2502
2503     WriteLock(&source->queue_lock);
2504     /* Find the new buffer queue head */
2505     NewHead = ATOMIC_LOAD(&source->queue);
2506     Current = ATOMIC_LOAD(&source->current_buffer);
2507     for(i = 0;i < nb && NewHead;i++)
2508     {
2509         if(NewHead == Current)
2510             break;
2511         NewHead = NewHead->next;
2512     }
2513     if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2514     {
2515         WriteUnlock(&source->queue_lock);
2516         /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2517         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2518     }
2519
2520     /* Swap it, and cut the new head from the old. */
2521     OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead);
2522     if(NewHead)
2523     {
2524         ALCdevice *device = context->Device;
2525         ALbufferlistitem *OldTail = NewHead->prev;
2526         uint count;
2527
2528         /* Cut the new head's link back to the old body. The mixer is robust
2529          * enough to handle the link back going away. Once the active mix (if
2530          * any) is complete, it's safe to finish cutting the old tail from the
2531          * new head. */
2532         NewHead->prev = NULL;
2533         if(((count=ReadRef(&device->MixCount))&1) != 0)
2534         {
2535             while(count == ReadRef(&device->MixCount))
2536                 althrd_yield();
2537         }
2538         OldTail->next = NULL;
2539     }
2540     WriteUnlock(&source->queue_lock);
2541
2542     while(OldHead != NULL)
2543     {
2544         ALbufferlistitem *next = OldHead->next;
2545         ALbuffer *buffer = OldHead->buffer;
2546
2547         if(!buffer)
2548             *(buffers++) = 0;
2549         else
2550         {
2551             *(buffers++) = buffer->id;
2552             DecrementRef(&buffer->ref);
2553         }
2554
2555         free(OldHead);
2556         OldHead = next;
2557     }
2558
2559 done:
2560     ALCcontext_DecRef(context);
2561 }
2562
2563
2564 static ALvoid InitSourceParams(ALsource *Source)
2565 {
2566     ALuint i;
2567
2568     RWLockInit(&Source->queue_lock);
2569
2570     Source->InnerAngle = 360.0f;
2571     Source->OuterAngle = 360.0f;
2572     Source->Pitch = 1.0f;
2573     aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f);
2574     aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
2575     aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f);
2576     Source->Orientation[0][0] =  0.0f;
2577     Source->Orientation[0][1] =  0.0f;
2578     Source->Orientation[0][2] = -1.0f;
2579     Source->Orientation[1][0] =  0.0f;
2580     Source->Orientation[1][1] =  1.0f;
2581     Source->Orientation[1][2] =  0.0f;
2582     Source->RefDistance = 1.0f;
2583     Source->MaxDistance = FLT_MAX;
2584     Source->RollOffFactor = 1.0f;
2585     Source->Looping = AL_FALSE;
2586 #ifdef __TIZEN__
2587     Source->LoopCount = 1;
2588 #endif
2589     Source->Gain = 1.0f;
2590     Source->MinGain = 0.0f;
2591     Source->MaxGain = 1.0f;
2592     Source->OuterGain = 0.0f;
2593     Source->OuterGainHF = 1.0f;
2594
2595     Source->DryGainHFAuto = AL_TRUE;
2596     Source->WetGainAuto = AL_TRUE;
2597     Source->WetGainHFAuto = AL_TRUE;
2598     Source->AirAbsorptionFactor = 0.0f;
2599     Source->RoomRolloffFactor = 0.0f;
2600     Source->DopplerFactor = 1.0f;
2601     Source->DirectChannels = AL_FALSE;
2602
2603     Source->Radius = 0.0f;
2604
2605     Source->DistanceModel = DefaultDistanceModel;
2606
2607     Source->state = AL_INITIAL;
2608     Source->new_state = AL_NONE;
2609     Source->SourceType = AL_UNDETERMINED;
2610     Source->Offset = -1.0;
2611
2612     ATOMIC_INIT(&Source->queue, NULL);
2613     ATOMIC_INIT(&Source->current_buffer, NULL);
2614
2615     Source->Direct.Gain = 1.0f;
2616     Source->Direct.GainHF = 1.0f;
2617     Source->Direct.HFReference = LOWPASSFREQREF;
2618     Source->Direct.GainLF = 1.0f;
2619     Source->Direct.LFReference = HIGHPASSFREQREF;
2620     for(i = 0;i < MAX_SENDS;i++)
2621     {
2622         Source->Send[i].Gain = 1.0f;
2623         Source->Send[i].GainHF = 1.0f;
2624         Source->Send[i].HFReference = LOWPASSFREQREF;
2625         Source->Send[i].GainLF = 1.0f;
2626         Source->Send[i].LFReference = HIGHPASSFREQREF;
2627     }
2628
2629     ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
2630 }
2631
2632
2633 /* SetSourceState
2634  *
2635  * Sets the source's new play state given its current state.
2636  */
2637 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2638 {
2639     WriteLock(&Source->queue_lock);
2640     if(state == AL_PLAYING)
2641     {
2642         ALCdevice *device = Context->Device;
2643         ALbufferlistitem *BufferList;
2644         ALboolean discontinuity;
2645         ALvoice *voice = NULL;
2646         ALsizei i;
2647
2648         /* Check that there is a queue containing at least one valid, non zero
2649          * length Buffer. */
2650         BufferList = ATOMIC_LOAD(&Source->queue);
2651         while(BufferList)
2652         {
2653             ALbuffer *buffer;
2654             if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2655                 break;
2656             BufferList = BufferList->next;
2657         }
2658
2659         if(Source->state != AL_PAUSED)
2660         {
2661             Source->state = AL_PLAYING;
2662             Source->position = 0;
2663             Source->position_fraction = 0;
2664             ATOMIC_STORE(&Source->current_buffer, BufferList);
2665             discontinuity = AL_TRUE;
2666         }
2667         else
2668         {
2669             Source->state = AL_PLAYING;
2670             discontinuity = AL_FALSE;
2671         }
2672
2673         // Check if an Offset has been set
2674         if(Source->Offset >= 0.0)
2675         {
2676             ApplyOffset(Source);
2677             /* discontinuity = AL_TRUE;??? */
2678         }
2679
2680         /* If there's nothing to play, or device is disconnected, go right to
2681          * stopped */
2682         if(!BufferList || !device->Connected)
2683             goto do_stop;
2684
2685         /* Make sure this source isn't already active, while looking for an
2686          * unused active source slot to put it in. */
2687         for(i = 0;i < Context->VoiceCount;i++)
2688         {
2689             ALsource *old = Source;
2690             if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2691             {
2692                 if(voice == NULL)
2693                 {
2694                     voice = &Context->Voices[i];
2695                     voice->Source = Source;
2696                 }
2697                 break;
2698             }
2699             old = NULL;
2700             if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2701                 voice = &Context->Voices[i];
2702         }
2703         if(voice == NULL)
2704         {
2705             voice = &Context->Voices[Context->VoiceCount++];
2706             voice->Source = Source;
2707         }
2708
2709         /* Clear previous samples if playback is discontinuous. */
2710         if(discontinuity)
2711             memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2712
2713         voice->Direct.Moving  = AL_FALSE;
2714         voice->Direct.Counter = 0;
2715         for(i = 0;i < MAX_INPUT_CHANNELS;i++)
2716         {
2717             ALsizei j;
2718             for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
2719                 voice->Direct.Hrtf[i].State.History[j] = 0.0f;
2720             for(j = 0;j < HRIR_LENGTH;j++)
2721             {
2722                 voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f;
2723                 voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f;
2724             }
2725         }
2726         for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
2727         {
2728             voice->Send[i].Moving  = AL_FALSE;
2729             voice->Send[i].Counter = 0;
2730         }
2731
2732         if(BufferList->buffer->FmtChannels == FmtMono)
2733             voice->Update = CalcSourceParams;
2734         else
2735             voice->Update = CalcNonAttnSourceParams;
2736
2737         ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
2738     }
2739     else if(state == AL_PAUSED)
2740     {
2741         if(Source->state == AL_PLAYING)
2742             Source->state = AL_PAUSED;
2743     }
2744     else if(state == AL_STOPPED)
2745     {
2746     do_stop:
2747         if(Source->state != AL_INITIAL)
2748         {
2749             Source->state = AL_STOPPED;
2750             ATOMIC_STORE(&Source->current_buffer, NULL);
2751         }
2752         Source->Offset = -1.0;
2753     }
2754     else if(state == AL_INITIAL)
2755     {
2756         if(Source->state != AL_INITIAL)
2757         {
2758             Source->state = AL_INITIAL;
2759             Source->position = 0;
2760             Source->position_fraction = 0;
2761             ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
2762         }
2763         Source->Offset = -1.0;
2764     }
2765     WriteUnlock(&Source->queue_lock);
2766 }
2767
2768 /* GetSourceSampleOffset
2769  *
2770  * Gets the current read offset for the given Source, in 32.32 fixed-point
2771  * samples. The offset is relative to the start of the queue (not the start of
2772  * the current buffer).
2773  */
2774 ALint64 GetSourceSampleOffset(ALsource *Source)
2775 {
2776     const ALbufferlistitem *BufferList;
2777     const ALbufferlistitem *Current;
2778     ALuint64 readPos;
2779
2780     ReadLock(&Source->queue_lock);
2781     if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2782     {
2783         ReadUnlock(&Source->queue_lock);
2784         return 0;
2785     }
2786
2787     /* NOTE: This is the offset into the *current* buffer, so add the length of
2788      * any played buffers */
2789     readPos  = (ALuint64)Source->position << 32;
2790     readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2791     BufferList = ATOMIC_LOAD(&Source->queue);
2792     Current = ATOMIC_LOAD(&Source->current_buffer);
2793     while(BufferList && BufferList != Current)
2794     {
2795         if(BufferList->buffer)
2796             readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2797         BufferList = BufferList->next;
2798     }
2799
2800     ReadUnlock(&Source->queue_lock);
2801     return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2802 }
2803
2804 /* GetSourceSecOffset
2805  *
2806  * Gets the current read offset for the given Source, in seconds. The offset is
2807  * relative to the start of the queue (not the start of the current buffer).
2808  */
2809 static ALdouble GetSourceSecOffset(ALsource *Source)
2810 {
2811     const ALbufferlistitem *BufferList;
2812     const ALbufferlistitem *Current;
2813     const ALbuffer *Buffer = NULL;
2814     ALuint64 readPos;
2815
2816     ReadLock(&Source->queue_lock);
2817     if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2818     {
2819         ReadUnlock(&Source->queue_lock);
2820         return 0.0;
2821     }
2822
2823     /* NOTE: This is the offset into the *current* buffer, so add the length of
2824      * any played buffers */
2825     readPos  = (ALuint64)Source->position << FRACTIONBITS;
2826     readPos |= (ALuint64)Source->position_fraction;
2827     BufferList = ATOMIC_LOAD(&Source->queue);
2828     Current = ATOMIC_LOAD(&Source->current_buffer);
2829     while(BufferList && BufferList != Current)
2830     {
2831         const ALbuffer *buffer = BufferList->buffer;
2832         if(buffer != NULL)
2833         {
2834             if(!Buffer) Buffer = buffer;
2835             readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2836         }
2837         BufferList = BufferList->next;
2838     }
2839
2840     while(BufferList && !Buffer)
2841     {
2842         Buffer = BufferList->buffer;
2843         BufferList = BufferList->next;
2844     }
2845     assert(Buffer != NULL);
2846
2847     ReadUnlock(&Source->queue_lock);
2848     return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2849 }
2850
2851 /* GetSourceOffsets
2852  *
2853  * Gets the current read and write offsets for the given Source, in the
2854  * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2855  * the start of the queue (not the start of the current buffer).
2856  */
2857 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2858 {
2859     const ALbufferlistitem *BufferList;
2860     const ALbufferlistitem *Current;
2861     const ALbuffer *Buffer = NULL;
2862     ALboolean readFin = AL_FALSE;
2863     ALuint readPos, readPosFrac, writePos;
2864     ALuint totalBufferLen;
2865
2866     ReadLock(&Source->queue_lock);
2867     if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2868     {
2869         offset[0] = 0.0;
2870         offset[1] = 0.0;
2871         ReadUnlock(&Source->queue_lock);
2872         return;
2873     }
2874
2875     if(updateLen > 0.0 && updateLen < 0.015)
2876         updateLen = 0.015;
2877
2878     /* NOTE: This is the offset into the *current* buffer, so add the length of
2879      * any played buffers */
2880     totalBufferLen = 0;
2881     readPos = Source->position;
2882     readPosFrac = Source->position_fraction;
2883     BufferList = ATOMIC_LOAD(&Source->queue);
2884     Current = ATOMIC_LOAD(&Source->current_buffer);
2885     while(BufferList != NULL)
2886     {
2887         const ALbuffer *buffer;
2888         readFin = readFin || (BufferList == Current);
2889         if((buffer=BufferList->buffer) != NULL)
2890         {
2891             if(!Buffer) Buffer = buffer;
2892             totalBufferLen += buffer->SampleLen;
2893             if(!readFin) readPos += buffer->SampleLen;
2894         }
2895         BufferList = BufferList->next;
2896     }
2897     assert(Buffer != NULL);
2898
2899     if(Source->state == AL_PLAYING)
2900         writePos = readPos + (ALuint)(updateLen*Buffer->Frequency + 0.5f);
2901     else
2902         writePos = readPos;
2903
2904     if(Source->Looping)
2905     {
2906         readPos %= totalBufferLen;
2907         writePos %= totalBufferLen;
2908     }
2909     else
2910     {
2911         /* Wrap positions back to 0 */
2912         if(readPos >= totalBufferLen)
2913             readPos = readPosFrac = 0;
2914         if(writePos >= totalBufferLen)
2915             writePos = 0;
2916     }
2917
2918     switch(name)
2919     {
2920         case AL_SEC_OFFSET:
2921             offset[0] = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
2922             offset[1] = (ALdouble)writePos/Buffer->Frequency;
2923             break;
2924
2925         case AL_SAMPLE_OFFSET:
2926         case AL_SAMPLE_RW_OFFSETS_SOFT:
2927             offset[0] = readPos + (ALdouble)readPosFrac/FRACTIONONE;
2928             offset[1] = (ALdouble)writePos;
2929             break;
2930
2931         case AL_BYTE_OFFSET:
2932         case AL_BYTE_RW_OFFSETS_SOFT:
2933             if(Buffer->OriginalType == UserFmtIMA4)
2934             {
2935                 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2936                 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2937                 ALuint FrameBlockSize = Buffer->OriginalAlign;
2938
2939                 /* Round down to nearest ADPCM block */
2940                 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2941                 if(Source->state != AL_PLAYING)
2942                     offset[1] = offset[0];
2943                 else
2944                 {
2945                     /* Round up to nearest ADPCM block */
2946                     offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2947                                            FrameBlockSize * BlockSize);
2948                 }
2949             }
2950             else if(Buffer->OriginalType == UserFmtMSADPCM)
2951             {
2952                 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2953                 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2954                 ALuint FrameBlockSize = Buffer->OriginalAlign;
2955
2956                 /* Round down to nearest ADPCM block */
2957                 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2958                 if(Source->state != AL_PLAYING)
2959                     offset[1] = offset[0];
2960                 else
2961                 {
2962                     /* Round up to nearest ADPCM block */
2963                     offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2964                                            FrameBlockSize * BlockSize);
2965                 }
2966             }
2967             else
2968             {
2969                 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2970                 offset[0] = (ALdouble)(readPos * FrameSize);
2971                 offset[1] = (ALdouble)(writePos * FrameSize);
2972             }
2973             break;
2974     }
2975
2976     ReadUnlock(&Source->queue_lock);
2977 }
2978
2979
2980 /* ApplyOffset
2981  *
2982  * Apply the stored playback offset to the Source. This function will update
2983  * the number of buffers "played" given the stored offset.
2984  */
2985 ALboolean ApplyOffset(ALsource *Source)
2986 {
2987     ALbufferlistitem *BufferList;
2988     const ALbuffer *Buffer;
2989     ALuint bufferLen, totalBufferLen;
2990     ALuint offset=0, frac=0;
2991
2992     /* Get sample frame offset */
2993     if(!GetSampleOffset(Source, &offset, &frac))
2994         return AL_FALSE;
2995
2996     totalBufferLen = 0;
2997     BufferList = ATOMIC_LOAD(&Source->queue);
2998     while(BufferList && totalBufferLen <= offset)
2999     {
3000         Buffer = BufferList->buffer;
3001         bufferLen = Buffer ? Buffer->SampleLen : 0;
3002
3003         if(bufferLen > offset-totalBufferLen)
3004         {
3005             /* Offset is in this buffer */
3006             ATOMIC_STORE(&Source->current_buffer, BufferList);
3007
3008             Source->position = offset - totalBufferLen;
3009             Source->position_fraction = frac;
3010             return AL_TRUE;
3011         }
3012
3013         totalBufferLen += bufferLen;
3014
3015         BufferList = BufferList->next;
3016     }
3017
3018     /* Offset is out of range of the queue */
3019     return AL_FALSE;
3020 }
3021
3022
3023 /* GetSampleOffset
3024  *
3025  * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3026  * or Second offset supplied by the application). This takes into account the
3027  * fact that the buffer format may have been modifed since.
3028  */
3029 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
3030 {
3031     const ALbuffer *Buffer = NULL;
3032     const ALbufferlistitem *BufferList;
3033     ALdouble dbloff, dblfrac;
3034
3035     /* Find the first valid Buffer in the Queue */
3036     BufferList = ATOMIC_LOAD(&Source->queue);
3037     while(BufferList)
3038     {
3039         if(BufferList->buffer)
3040         {
3041             Buffer = BufferList->buffer;
3042             break;
3043         }
3044         BufferList = BufferList->next;
3045     }
3046     if(!Buffer)
3047     {
3048         Source->Offset = -1.0;
3049         return AL_FALSE;
3050     }
3051
3052     switch(Source->OffsetType)
3053     {
3054     case AL_BYTE_OFFSET:
3055         /* Determine the ByteOffset (and ensure it is block aligned) */
3056         *offset = (ALuint)Source->Offset;
3057         if(Buffer->OriginalType == UserFmtIMA4)
3058         {
3059             ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3060             *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3061             *offset *= Buffer->OriginalAlign;
3062         }
3063         else if(Buffer->OriginalType == UserFmtMSADPCM)
3064         {
3065             ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3066             *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3067             *offset *= Buffer->OriginalAlign;
3068         }
3069         else
3070             *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3071         *frac = 0;
3072         break;
3073
3074     case AL_SAMPLE_OFFSET:
3075         dblfrac = modf(Source->Offset, &dbloff);
3076         *offset = (ALuint)mind(dbloff, UINT_MAX);
3077         *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3078         break;
3079
3080     case AL_SEC_OFFSET:
3081         dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3082         *offset = (ALuint)mind(dbloff, UINT_MAX);
3083         *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3084         break;
3085     }
3086     Source->Offset = -1.0;
3087
3088     return AL_TRUE;
3089 }
3090
3091
3092 /* ReleaseALSources
3093  *
3094  * Destroys all sources in the source map.
3095  */
3096 ALvoid ReleaseALSources(ALCcontext *Context)
3097 {
3098     ALbufferlistitem *item;
3099     ALsizei pos;
3100     ALuint j;
3101     for(pos = 0;pos < Context->SourceMap.size;pos++)
3102     {
3103         ALsource *temp = Context->SourceMap.array[pos].value;
3104         Context->SourceMap.array[pos].value = NULL;
3105
3106         item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
3107         while(item != NULL)
3108         {
3109             ALbufferlistitem *next = item->next;
3110             if(item->buffer != NULL)
3111                 DecrementRef(&item->buffer->ref);
3112             free(item);
3113             item = next;
3114         }
3115
3116         for(j = 0;j < MAX_SENDS;++j)
3117         {
3118             if(temp->Send[j].Slot)
3119                 DecrementRef(&temp->Send[j].Slot->ref);
3120             temp->Send[j].Slot = NULL;
3121         }
3122
3123         FreeThunkEntry(temp->id);
3124         memset(temp, 0, sizeof(*temp));
3125         al_free(temp);
3126     }
3127 }