summaryrefslogtreecommitdiffstats
path: root/mpg123_artsplugin/mpg123/buffer.c
blob: 33b4c92b148bcb074aea7bb654cde76b00f4f847 (plain)
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
236
237
238
239
240
241
242
243
244
245
/*
 *   buffer.c
 *
 *   Oliver Fromme  <oliver.fromme@heim3.tu-clausthal.de>
 *   Mon Apr 14 03:53:18 MET DST 1997
 */

#include <stdlib.h>
#include <errno.h>

#include "mpg123.h"

int outburst = MAXOUTBURST;
int preload;

static int intflag = FALSE;
static int usr1flag = FALSE;

static void catch_interrupt (void)
{
	intflag = TRUE;
}

static void catch_usr1 (void)
{
	usr1flag = TRUE;
}

/* Interfaces to writer process */

extern void buffer_sig(int signal, int block);

void buffer_ignore_lowmem(void)
{
#ifndef NOXFERMEM
	if(buffermem->wakeme[XF_READER])
		xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_WAKEUP);
#endif
}

void buffer_end(void)
{
#ifndef NOXFERMEM
	xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_TERMINATE);
#endif
}

void buffer_resync(void)
{
	buffer_sig(SIGINT, TRUE);
}

void buffer_reset(void)
{
	buffer_sig(SIGUSR1, TRUE);
}

void buffer_start(void)
{
	buffer_sig(SIGCONT, FALSE);
}

void buffer_stop(void)
{
	buffer_sig(SIGSTOP, FALSE);
}

extern int buffer_pid;

void buffer_sig(int signal, int block)
{
	
#ifndef NOXFERMEM
	
	kill(buffer_pid, signal);
	
	if (!buffermem || !block)
		return;

	if(xfermem_block(XF_WRITER, buffermem) != XF_CMD_WAKEUP) 
		perror("Could not resync/reset buffers");
#endif
	
	return;
}

#ifndef NOXFERMEM

void buffer_loop(struct audio_info_struct *ai, sigset_t *oldsigset)
{
	int bytes;
	int my_fd = buffermem->fd[XF_READER];
	txfermem *xf = buffermem;
	int done = FALSE;

	catchsignal (SIGINT, catch_interrupt);
	catchsignal (SIGUSR1, catch_usr1);
	sigproctqmask (SIG_SETMASK, oldsigset, NULL);
#ifndef NO_DECODE_AUDIO
	if (param.outmode == DECODE_AUDIO) {
		if (audio_open(ai) < 0) {
			perror("audio");
			exit(1);
		}
	}
#endif

	for (;;) {
		if (intflag) {
			intflag = FALSE;
#ifndef NO_DECODE_AUDIO
			if (param.outmode == DECODE_AUDIO)
				audio_queueflush (ai);
#endif
			xf->readindex = xf->freeindex;
			if (xf->wakeme[XF_WRITER])
				xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
		}
		if (usr1flag) {
			usr1flag = FALSE;
			/*   close and re-open in order to flush
			 *   the device's internal buffer before
			 *   changing the sample rate.   [OF]
			 */
			/* writer must block when sending SIGUSR1
			 * or we will lose all data processed 
			 * in the meantime! [dk]
			 */
			xf->readindex = xf->freeindex;
			/* We've nailed down the new starting location -
			 * writer is now safe to go on. [dk]
			 */
			if (xf->wakeme[XF_WRITER])
				xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
#ifndef NO_DECODE_AUDIO
			if (param.outmode == DECODE_AUDIO) {
				audio_close (ai);
				ai->rate = xf->buf[0]; 
				ai->channels = xf->buf[1]; 
				ai->format = xf->buf[2];
				if (audio_open(ai) < 0) {
					sleep(1);
					/* give em a 2. try */
					if (audio_open(ai) < 0) {
						perror("audio");
						exit(1);
					}
				}
			}
#endif
		}
		if ( (bytes = xfermem_get_usedspace(xf)) < outburst ) {
			/* if we got a buffer underrun we first
			 * fill 1/8 of the buffer before continue/start
			 * playing */
			preload = xf->size>>3;
			if(preload < outburst)
				preload = outburst;
		}
		if(bytes < preload) {
			int cmd;
			if (done && !bytes) { 
				break;
			}

			if(!done) {

				cmd = xfermem_block(XF_READER, xf);

				switch(cmd) {

					/* More input pending. */
					case XF_CMD_WAKEUP_INFO:
						continue;
					/* Yes, we know buffer is low but
					 * know we don't care.
					 */
					case XF_CMD_WAKEUP:
						break;	/* Proceed playing. */
					case XF_CMD_TERMINATE:
						/* Proceed playing without 
						 * blocking any further.
						 */
						done=TRUE;
						break;
					case -1:
						if(errno==EINTR)
							continue;
						perror("Yuck! Error in buffer handling...");
						done = TRUE;
						xf->readindex = xf->freeindex;
						xfermem_putcmd(xf->fd[XF_READER], XF_CMD_TERMINATE);
						break;
					default:
						fprintf(stderr, "\nEh!? Received unknown command 0x%x in buffer process. Tell Daniel!\n", cmd);
				}
			}
		}
		preload = outburst; /* set preload to lower mark */
		if (bytes > xf->size - xf->readindex)
			bytes = xf->size - xf->readindex;
		if (bytes > outburst)
			bytes = outburst;

		if (param.outmode == DECODE_FILE)
			bytes = write(OutputDescriptor, xf->data + xf->readindex, bytes);
#ifndef NO_DECODE_AUDIO
		else if (param.outmode == DECODE_AUDIO)
			bytes = audio_play_samples(ai,
				(unsigned char *) (xf->data + xf->readindex), bytes);
#endif

		if(bytes < 0) {
			bytes = 0;
			if(errno != EINTR) {
				perror("Ouch ... error while writing audio data: ");
				/*
				 * done==TRUE tells writer process to stop
				 * sending data. There might be some latency
				 * involved when resetting readindex to 
				 * freeindex so we might need more than one
				 * cycle to terminate. (The number of cycles
				 * should be finite unless I managed to mess
				 * up something. ;-) [dk]
				 */
				done = TRUE;	
				xf->readindex = xf->freeindex;
				xfermem_putcmd(xf->fd[XF_READER], XF_CMD_TERMINATE);
			}
		}

		xf->readindex = (xf->readindex + bytes) % xf->size;
		if (xf->wakeme[XF_WRITER])
			xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
	}

#ifndef NO_DECODE_AUDIO
	if (param.outmode == DECODE_AUDIO)
		audio_close (ai);
#endif
}

#endif

/* EOF */