forked from mozilla/gecko-dev
-
Notifications
You must be signed in to change notification settings - Fork 2
/
bug525401_drain_deadlock.patch
235 lines (197 loc) · 6.17 KB
/
bug525401_drain_deadlock.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
diff --git a/media/libsydneyaudio/src/sydney_audio_alsa.c b/media/libsydneyaudio/src/sydney_audio_alsa.c
--- a/media/libsydneyaudio/src/sydney_audio_alsa.c
+++ b/media/libsydneyaudio/src/sydney_audio_alsa.c
@@ -315,16 +315,19 @@ sa_stream_resume(sa_stream_t *s) {
int
sa_stream_drain(sa_stream_t *s)
{
if (s == NULL || s->output_unit == NULL) {
return SA_ERROR_NO_INIT;
}
+ if (snd_pcm_state(s->output_unit) != SND_PCM_STATE_RUNNING) {
+ return SA_ERROR_INVALID;
+ }
snd_pcm_drain(s->output_unit);
return SA_SUCCESS;
}
/*
* -----------------------------------------------------------------------------
diff --git a/media/libsydneyaudio/src/sydney_audio_mac.c b/media/libsydneyaudio/src/sydney_audio_mac.c
--- a/media/libsydneyaudio/src/sydney_audio_mac.c
+++ b/media/libsydneyaudio/src/sydney_audio_mac.c
@@ -396,20 +396,20 @@ sa_stream_write(sa_stream_t *s, const vo
/*
* Once we have our first block of audio data, enable the audio callback
* function. This doesn't need to be protected by the mutex, because
* s->playing is not used in the audio callback thread, and it's probably
* better not to be inside the lock when we enable the audio callback.
*/
if (!s->playing) {
+ if (AudioOutputUnitStart(s->output_unit) != 0) {
+ return SA_ERROR_SYSTEM;
+ }
s->playing = TRUE;
- if (AudioOutputUnitStart(s->output_unit) != 0) {
- result = SA_ERROR_SYSTEM;
- }
}
return result;
}
static OSStatus
audio_callback(
@@ -553,17 +553,20 @@ sa_stream_pause(sa_stream_t *s) {
}
/*
* Don't hold the mutex when stopping the audio device, because it is
* possible to deadlock with this thread holding mutex then waiting on an
* internal Core Audio lock, and with the callback thread holding the Core
* Audio lock and waiting on the mutex.
*/
- AudioOutputUnitStop(s->output_unit);
+ if (AudioOutputUnitStop(s->output_unit) != 0) {
+ return SA_ERROR_SYSTEM;
+ }
+ s->playing = FALSE;
return SA_SUCCESS;
}
int
sa_stream_resume(sa_stream_t *s) {
@@ -581,17 +584,20 @@ sa_stream_resume(sa_stream_t *s) {
pthread_mutex_unlock(&s->mutex);
/*
* Don't hold the mutex when starting the audio device, because it is
* possible to deadlock with this thread holding mutex then waiting on an
* internal Core Audio lock, and with the callback thread holding the Core
* Audio lock and waiting on the mutex.
*/
- AudioOutputUnitStart(s->output_unit);
+ if (AudioOutputUnitStart(s->output_unit) != 0) {
+ return SA_ERROR_SYSTEM;
+ }
+ s->playing = TRUE;
return SA_SUCCESS;
}
static sa_buf *
new_buffer(void) {
sa_buf * b = malloc(sizeof(sa_buf) + BUF_SIZE);
@@ -607,16 +613,20 @@ new_buffer(void) {
int
sa_stream_drain(sa_stream_t *s)
{
if (s == NULL || s->output_unit == NULL) {
return SA_ERROR_NO_INIT;
}
+ if (!s->playing) {
+ return SA_ERROR_INVALID;
+ }
+
while (1) {
pthread_mutex_lock(&s->mutex);
sa_buf * b;
size_t used = 0;
for (b = s->bl_head; b != NULL; b = b->next) {
used += b->end - b->start;
}
pthread_mutex_unlock(&s->mutex);
diff --git a/media/libsydneyaudio/src/sydney_audio_waveapi.c b/media/libsydneyaudio/src/sydney_audio_waveapi.c
--- a/media/libsydneyaudio/src/sydney_audio_waveapi.c
+++ b/media/libsydneyaudio/src/sydney_audio_waveapi.c
@@ -111,16 +111,18 @@ struct sa_stream {
sa_pcm_format_t format;
HWAVEOUT hWaveOut;
HANDLE callbackEvent;
CRITICAL_SECTION waveCriticalSection;
WAVEHDR* waveBlocks;
volatile int waveFreeBlockCount;
int waveCurrentBlock;
+
+ int playing;
};
/** Forward definitions of audio api specific functions */
int allocateBlocks(int size, int count, WAVEHDR** blocks);
int freeBlocks(WAVEHDR* blocks);
int openAudio(sa_stream_t *s);
int closeAudio(sa_stream_t * s);
@@ -157,16 +159,17 @@ int sa_stream_create_pcm(sa_stream_t **s
}
_s->rwMode = mode;
_s->format = format;
_s->rate = rate;
_s->channels = nchannels;
_s->deviceName = DEFAULT_DEVICE_NAME;
_s->device = DEFAULT_DEVICE;
+ _s->playing = 0;
*s = _s;
return SA_SUCCESS;
}
/** Initialise the device */
int sa_stream_open(sa_stream_t *s) {
int status = SA_SUCCESS;
@@ -300,33 +303,41 @@ int sa_stream_get_position(sa_stream_t *
int sa_stream_resume(sa_stream_t *s) {
int status;
ERROR_IF_NO_INIT(s);
status = waveOutRestart(s->hWaveOut);
HANDLE_WAVE_ERROR(status, "resuming audio playback");
+ s->playing = 1;
+
return SA_SUCCESS;
}
/** Pause audio playback (do not empty the buffer) */
int sa_stream_pause(sa_stream_t *s) {
int status;
ERROR_IF_NO_INIT(s);
status = waveOutPause(s->hWaveOut);
HANDLE_WAVE_ERROR(status, "resuming audio playback");
+ s->playing = 0;
+
return SA_SUCCESS;
}
/** Block until all audio has been played */
int sa_stream_drain(sa_stream_t *s) {
ERROR_IF_NO_INIT(s);
+ if (!s->playing) {
+ return SA_ERROR_INVALID;
+ }
+
/* wait for all blocks to complete */
EnterCriticalSection(&(s->waveCriticalSection));
while(s->waveFreeBlockCount < BLOCK_COUNT) {
LeaveCriticalSection(&(s->waveCriticalSection));
Sleep(10);
EnterCriticalSection(&(s->waveCriticalSection));
}
LeaveCriticalSection(&(s->waveCriticalSection));
@@ -484,16 +495,18 @@ int closeAudio(sa_stream_t * s) {
s->waveBlocks = NULL;
}
status = waveOutClose(s->hWaveOut);
if (status != MMSYSERR_NOERROR) {
result = getSAErrorCode(status);
}
+ s->playing = 0;
+
DeleteCriticalSection(&(s->waveCriticalSection));
CloseHandle(s->callbackEvent);
return result;
}
/**
* \brief - writes PCM audio samples to audio device
* \param s - valid handle to opened sydney stream
@@ -545,16 +558,18 @@ int writeAudio(sa_stream_t *s, LPSTR dat
/*
* point to the next block
*/
(s->waveCurrentBlock)++;
(s->waveCurrentBlock) %= BLOCK_COUNT;
current = &(s->waveBlocks[s->waveCurrentBlock]);
current->dwUser = 0;
+
+ s->playing = 1;
}
return SA_SUCCESS;
}
/**
* \brief - audio callback function called when next WAVE header is played by audio device
*/
void CALLBACK waveOutProc(