Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
4b888861
Commit
4b888861
authored
Jan 27, 2012
by
Jörg Höhle
Committed by
Alexandre Julliard
Jan 31, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
winecoreaudio: Implement a lock-free callback design.
parent
c9950119
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
81 additions
and
50 deletions
+81
-50
mmdevdrv.c
dlls/winecoreaudio.drv/mmdevdrv.c
+81
-50
No files found.
dlls/winecoreaudio.drv/mmdevdrv.c
View file @
4b888861
...
...
@@ -75,6 +75,7 @@ typedef struct _QueuedBufInfo {
typedef
struct
_AQBuffer
{
AudioQueueBufferRef
buf
;
struct
list
entry
;
BOOL
used
;
}
AQBuffer
;
struct
ACImpl
;
...
...
@@ -145,12 +146,9 @@ struct ACImpl {
struct
list
entry
;
struct
list
avail_buffers
;
struct
list
queued_buffers
;
/* either in avail, queued or public_buffer */
struct
list
queued_bufinfos
;
/* We can't use debug printing or {Enter,Leave}CriticalSection from
* OSX callback threads, so we use OSX's OSSpinLock for synchronization
* instead. OSSpinLock is not a recursive lock, so don't call
* synchronized functions while holding the lock. */
OSSpinLock
lock
;
};
...
...
@@ -191,8 +189,7 @@ static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
static
CRITICAL_SECTION
g_sessions_lock
=
{
&
g_sessions_lock_debug
,
-
1
,
0
,
0
,
0
,
0
};
static
struct
list
g_sessions
=
LIST_INIT
(
g_sessions
);
static
HRESULT
AudioClock_GetPosition_nolock
(
ACImpl
*
This
,
UINT64
*
pos
,
UINT64
*
qpctime
);
static
HRESULT
AudioCaptureClient_GetNextPacket
(
ACImpl
*
This
,
UINT32
*
frames
);
static
AudioSessionWrapper
*
AudioSessionWrapper_Create
(
ACImpl
*
client
);
static
HRESULT
ca_setvol
(
ACImpl
*
This
,
UINT32
index
);
...
...
@@ -487,6 +484,7 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
IMMDevice_AddRef
(
This
->
parent
);
list_init
(
&
This
->
avail_buffers
);
list_init
(
&
This
->
queued_buffers
);
list_init
(
&
This
->
queued_bufinfos
);
This
->
adevid
=
*
adevid
;
...
...
@@ -575,6 +573,20 @@ static UINT64 get_current_aqbuffer_position(ACImpl *This, int mode)
return
ret
;
}
static
void
avail_update
(
ACImpl
*
This
)
{
AQBuffer
*
buf
,
*
next
;
LIST_FOR_EACH_ENTRY_SAFE
(
buf
,
next
,
&
This
->
queued_buffers
,
AQBuffer
,
entry
){
if
(
buf
->
used
)
break
;
if
(
This
->
dataflow
==
eCapture
)
This
->
inbuf_frames
+=
buf
->
buf
->
mAudioDataByteSize
/
This
->
fmt
->
nBlockAlign
;
list_remove
(
&
buf
->
entry
);
list_add_tail
(
&
This
->
avail_buffers
,
&
buf
->
entry
);
}
}
static
HRESULT
WINAPI
AudioClient_QueryInterface
(
IAudioClient
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
...
...
@@ -622,6 +634,7 @@ static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
AudioQueueStop
(
This
->
aqueue
,
1
);
/* Stopped synchronously, all buffers returned. */
list_move_tail
(
&
This
->
avail_buffers
,
&
This
->
queued_buffers
);
LIST_FOR_EACH_ENTRY_SAFE
(
buf
,
next
,
&
This
->
avail_buffers
,
AQBuffer
,
entry
){
AudioQueueFreeBuffer
(
This
->
aqueue
,
buf
->
buf
);
HeapFree
(
GetProcessHeap
(),
0
,
buf
);
...
...
@@ -767,28 +780,26 @@ static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
return
S_OK
;
}
/* We can't use debug printing or {Enter,Leave}CriticalSection from
* OSX callback threads. We may use OSSpinLock.
* OSSpinLock is not a recursive lock, so don't call
* synchronized functions while holding the lock. */
static
void
ca_out_buffer_cb
(
void
*
user
,
AudioQueueRef
aqueue
,
AudioQueueBufferRef
buffer
)
{
ACImpl
*
This
=
user
;
AQBuffer
*
buf
=
buffer
->
mUserData
;
OSSpinLockLock
(
&
This
->
lock
);
list_add_tail
(
&
This
->
avail_buffers
,
&
buf
->
entry
);
OSSpinLockUnlock
(
&
This
->
lock
);
buf
->
used
=
FALSE
;
}
static
void
ca_in_buffer_cb
(
void
*
user
,
AudioQueueRef
aqueue
,
AudioQueueBufferRef
buffer
,
const
AudioTimeStamp
*
start
,
UInt32
ndesc
,
const
AudioStreamPacketDescription
*
descs
)
{
ACImpl
*
This
=
user
;
AQBuffer
*
buf
=
buffer
->
mUserData
;
OSSpinLockLock
(
&
This
->
lock
);
list_add_tail
(
&
This
->
avail_buffers
,
&
buf
->
entry
);
This
->
inbuf_frames
+=
buffer
->
mAudioDataByteSize
/
This
->
fmt
->
nBlockAlign
;
OSSpinLockUnlock
(
&
This
->
lock
);
buf
->
used
=
FALSE
;
/* let's update inbuf_frames synchronously without OSAddAtomic */
}
static
HRESULT
ca_setup_aqueue
(
AudioDeviceID
did
,
EDataFlow
flow
,
...
...
@@ -1037,12 +1048,13 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
}
buf
->
buf
->
mUserData
=
buf
;
buf
->
used
=
TRUE
;
sc
=
AudioQueueEnqueueBuffer
(
This
->
aqueue
,
buf
->
buf
,
0
,
NULL
);
if
(
sc
!=
noErr
){
ERR
(
"Couldn't enqueue buffer: %lx
\n
"
,
sc
);
break
;
}
list_add_tail
(
&
This
->
queued_buffers
,
&
buf
->
entry
);
}
}
...
...
@@ -1224,6 +1236,8 @@ static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
if
(
!
This
->
aqueue
)
return
AUDCLNT_E_NOT_INITIALIZED
;
avail_update
(
This
);
if
(
This
->
dataflow
==
eRender
){
UINT64
bufpos
;
bufpos
=
get_current_aqbuffer_position
(
This
,
BUFPOS_RELATIVE
);
...
...
@@ -1408,10 +1422,8 @@ void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
{
ACImpl
*
This
=
user
;
OSSpinLockLock
(
&
This
->
lock
);
if
(
This
->
event
)
SetEvent
(
This
->
event
);
OSSpinLockUnlock
(
&
This
->
lock
);
}
static
HRESULT
WINAPI
AudioClient_Start
(
IAudioClient
*
iface
)
...
...
@@ -1439,8 +1451,8 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
}
if
(
This
->
event
)
if
(
!
CreateTimerQueueTimer
(
&
This
->
timer
,
g_timer_q
,
ca_period_cb
,
This
,
0
,
This
->
period_ms
,
0
)){
if
(
!
CreateTimerQueueTimer
(
&
This
->
timer
,
g_timer_q
,
ca_period_cb
,
This
,
0
,
This
->
period_ms
,
WT_EXECUTEINTIMERTHREAD
)){
This
->
timer
=
NULL
;
OSSpinLockUnlock
(
&
This
->
lock
);
WARN
(
"Unable to create timer: %u
\n
"
,
GetLastError
());
...
...
@@ -1449,16 +1461,13 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
This
->
playing
=
StateInTransition
;
OSSpinLockUnlock
(
&
This
->
lock
);
sc
=
AudioQueueStart
(
This
->
aqueue
,
NULL
);
if
(
sc
!=
noErr
){
OSSpinLockUnlock
(
&
This
->
lock
);
WARN
(
"Unable to start audio queue: %lx
\n
"
,
sc
);
return
E_FAIL
;
}
OSSpinLockLock
(
&
This
->
lock
);
This
->
playing
=
StatePlaying
;
OSSpinLockUnlock
(
&
This
->
lock
);
...
...
@@ -1514,28 +1523,27 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
}
else
WARN
(
"GetCurrentTime failed: %lx
\n
"
,
sc
);
OSSpinLockUnlock
(
&
This
->
lock
);
if
(
event
&&
wait
)
WaitForSingleObject
(
event
,
INFINITE
);
CloseHandle
(
event
);
sc
=
AudioQueueFlush
(
This
->
aqueue
);
if
(
sc
!=
noErr
)
if
(
sc
!=
noErr
){
OSSpinLockUnlock
(
&
This
->
lock
);
WARN
(
"Unable to flush audio queue: %lx
\n
"
,
sc
);
}
sc
=
AudioQueuePause
(
This
->
aqueue
);
if
(
sc
!=
noErr
){
OSSpinLockUnlock
(
&
This
->
lock
);
WARN
(
"Unable to pause audio queue: %lx
\n
"
,
sc
);
return
E_FAIL
;
}
OSSpinLockLock
(
&
This
->
lock
);
This
->
playing
=
StateStopped
;
OSSpinLockUnlock
(
&
This
->
lock
);
if
(
event
&&
wait
)
WaitForSingleObject
(
event
,
INFINITE
);
CloseHandle
(
event
);
return
S_OK
;
}
...
...
@@ -1573,14 +1581,15 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
HeapFree
(
GetProcessHeap
(),
0
,
bufinfo
);
}
OSSpinLockUnlock
(
&
This
->
lock
);
sc
=
AudioQueueReset
(
This
->
aqueue
);
if
(
sc
!=
noErr
){
OSSpinLockUnlock
(
&
This
->
lock
);
WARN
(
"Unable to reset audio queue: %lx
\n
"
,
sc
);
return
E_FAIL
;
}
OSSpinLockUnlock
(
&
This
->
lock
);
return
S_OK
;
}
...
...
@@ -1754,7 +1763,7 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
{
ACImpl
*
This
=
impl_from_IAudioRenderClient
(
iface
);
AQBuffer
*
buf
;
UINT32
pad
,
bytes
=
frames
*
This
->
fmt
->
nBlockAlign
;
UINT32
pad
,
bytes
;
HRESULT
hr
;
OSStatus
sc
;
...
...
@@ -1787,6 +1796,7 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
return
AUDCLNT_E_BUFFER_TOO_LARGE
;
}
bytes
=
frames
*
This
->
fmt
->
nBlockAlign
;
LIST_FOR_EACH_ENTRY
(
buf
,
&
This
->
avail_buffers
,
AQBuffer
,
entry
){
if
(
buf
->
buf
->
mAudioDataBytesCapacity
>=
bytes
){
This
->
public_buffer
=
buf
->
buf
;
...
...
@@ -1799,9 +1809,10 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
sc
=
AudioQueueAllocateBuffer
(
This
->
aqueue
,
bytes
,
&
This
->
public_buffer
);
if
(
sc
!=
noErr
){
This
->
public_buffer
=
NULL
;
OSSpinLockUnlock
(
&
This
->
lock
);
WARN
(
"Unable to allocate buffer: %lx
\n
"
,
sc
);
return
E_
FAIL
;
return
E_
OUTOFMEMORY
;
}
buf
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
AQBuffer
));
if
(
!
buf
){
...
...
@@ -1810,13 +1821,13 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
OSSpinLockUnlock
(
&
This
->
lock
);
return
E_OUTOFMEMORY
;
}
buf
->
used
=
FALSE
;
buf
->
buf
=
This
->
public_buffer
;
This
->
public_buffer
->
mUserData
=
buf
;
}
*
data
=
This
->
public_buffer
->
mAudioData
;
This
->
getbuf_last
=
frames
;
*
data
=
This
->
public_buffer
->
mAudioData
;
OSSpinLockUnlock
(
&
This
->
lock
);
...
...
@@ -1827,6 +1838,7 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
IAudioRenderClient
*
iface
,
UINT32
frames
,
DWORD
flags
)
{
ACImpl
*
This
=
impl_from_IAudioRenderClient
(
iface
);
AQBuffer
*
buf
;
AudioTimeStamp
start_time
;
OSStatus
sc
;
...
...
@@ -1837,8 +1849,8 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
if
(
!
frames
){
This
->
getbuf_last
=
0
;
if
(
This
->
public_buffer
){
AQBuffer
*
buf
=
This
->
public_buffer
->
mUserData
;
list_add_
tail
(
&
This
->
avail_buffers
,
&
buf
->
entry
);
buf
=
This
->
public_buffer
->
mUserData
;
list_add_
head
(
&
This
->
avail_buffers
,
&
buf
->
entry
);
This
->
public_buffer
=
NULL
;
}
OSSpinLockUnlock
(
&
This
->
lock
);
...
...
@@ -1870,13 +1882,16 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
This
->
public_buffer
->
mAudioDataByteSize
=
frames
*
This
->
fmt
->
nBlockAlign
;
buf
=
This
->
public_buffer
->
mUserData
;
buf
->
used
=
TRUE
;
sc
=
AudioQueueEnqueueBufferWithParameters
(
This
->
aqueue
,
This
->
public_buffer
,
0
,
NULL
,
0
,
0
,
0
,
NULL
,
NULL
,
&
start_time
);
if
(
sc
!=
noErr
){
OSSpinLockUnlock
(
&
This
->
lock
);
WARN
(
"Unable to enqueue buffer: %lx
\n
"
,
sc
);
return
E_FAIL
;
ERR
(
"Unable to enqueue buffer: %lx
\n
"
,
sc
);
return
AUDCLNT_E_DEVICE_INVALIDATED
;
}
list_add_tail
(
&
This
->
queued_buffers
,
&
buf
->
entry
);
if
(
start_time
.
mFlags
&
kAudioTimeStampSampleTimeValid
){
QueuedBufInfo
*
bufinfo
;
...
...
@@ -1946,11 +1961,14 @@ static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
static
HRESULT
AudioCaptureClient_GetNextPacket
(
ACImpl
*
This
,
UINT32
*
frames
)
{
AQBuffer
*
buf
;
OSStatus
sc
;
avail_update
(
This
);
/* once, not inside loop */
for
(;;){
if
(
!
This
->
public_buffer
){
struct
list
*
head
=
list_head
(
&
This
->
avail_buffers
);
AQBuffer
*
buf
;
if
(
!
head
){
*
frames
=
0
;
...
...
@@ -1959,20 +1977,24 @@ static HRESULT AudioCaptureClient_GetNextPacket(ACImpl *This, UINT32 *frames)
buf
=
LIST_ENTRY
(
head
,
AQBuffer
,
entry
);
This
->
public_buffer
=
buf
->
buf
;
list_remove
(
&
buf
->
entry
);
}
}
else
buf
=
This
->
public_buffer
->
mUserData
;
*
frames
=
This
->
public_buffer
->
mAudioDataByteSize
/
This
->
fmt
->
nBlockAlign
;
if
(
*
frames
)
return
S_OK
;
WARN
(
"empty packet
\n
"
);
/* fixme: for reasons not yet understood, the initially submitted
* packets are returned with 0 bytes. Resubmit them. */
buf
->
used
=
TRUE
;
sc
=
AudioQueueEnqueueBuffer
(
This
->
aqueue
,
This
->
public_buffer
,
0
,
NULL
);
if
(
sc
!=
noErr
){
ERR
(
"Unable to enqueue buffer: %lx
\n
"
,
sc
);
/* Release will free This->public_buffer */
return
AUDCLNT_E_DEVICE_INVALIDATED
;
}
else
This
->
public_buffer
=
NULL
;
list_add_tail
(
&
This
->
queued_buffers
,
&
buf
->
entry
);
This
->
public_buffer
=
NULL
;
}
}
...
...
@@ -2003,14 +2025,17 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
}
if
((
This
->
getbuf_last
=
*
frames
)){
UINT64
pos
;
*
flags
=
0
;
*
data
=
This
->
public_buffer
->
mAudioData
;
if
(
devpos
)
*
devpos
=
This
->
written_frames
;
if
(
qpcpos
)
/* fixme: qpc of recording time */
AudioClock_GetPosition_nolock
(
This
,
&
pos
,
qpcpos
);
if
(
qpcpos
){
/* fixme: qpc of recording time */
LARGE_INTEGER
stamp
,
freq
;
QueryPerformanceCounter
(
&
stamp
);
QueryPerformanceFrequency
(
&
freq
);
*
qpcpos
=
(
stamp
.
QuadPart
*
(
INT64
)
10000000
)
/
freq
.
QuadPart
;
}
}
OSSpinLockUnlock
(
&
This
->
lock
);
...
...
@@ -2021,6 +2046,7 @@ static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
IAudioCaptureClient
*
iface
,
UINT32
done
)
{
ACImpl
*
This
=
impl_from_IAudioCaptureClient
(
iface
);
AQBuffer
*
buf
;
OSStatus
sc
;
TRACE
(
"(%p)->(%u)
\n
"
,
This
,
done
);
...
...
@@ -2047,6 +2073,8 @@ static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
This
->
inbuf_frames
-=
done
;
This
->
getbuf_last
=
0
;
buf
=
This
->
public_buffer
->
mUserData
;
buf
->
used
=
TRUE
;
sc
=
AudioQueueEnqueueBuffer
(
This
->
aqueue
,
This
->
public_buffer
,
0
,
NULL
);
if
(
sc
!=
noErr
){
OSSpinLockUnlock
(
&
This
->
lock
);
...
...
@@ -2054,7 +2082,8 @@ static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
* GetBuffer will see that packet again and again. */
ERR
(
"Unable to enqueue buffer: %lx
\n
"
,
sc
);
return
AUDCLNT_E_DEVICE_INVALIDATED
;
}
}
else
list_add_tail
(
&
This
->
queued_buffers
,
&
buf
->
entry
);
This
->
public_buffer
=
NULL
;
OSSpinLockUnlock
(
&
This
->
lock
);
...
...
@@ -2142,6 +2171,8 @@ static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
static
HRESULT
AudioClock_GetPosition_nolock
(
ACImpl
*
This
,
UINT64
*
pos
,
UINT64
*
qpctime
)
{
avail_update
(
This
);
if
(
This
->
dataflow
==
eRender
)
*
pos
=
get_current_aqbuffer_position
(
This
,
BUFPOS_ABSOLUTE
);
else
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment