shithub: qk1

Download patch

ref: 554f7a5c2fb8b4ac80034323e54c67ec12f8763a
parent: 00a30d4dc8de0929b982ed5d5e2ebd7d49df86e0
author: Sigrid Solveig Haflínudóttir <[email protected]>
date: Fri Dec 29 21:25:33 EST 2023

openal: create a thread instead of a process for track reading

--- a/snd_openal.c
+++ b/snd_openal.c
@@ -4,6 +4,7 @@
 #include <AL/alext.h>
 #include <sys/wait.h>
 #include <unistd.h>
+#include <pthread.h>
 
 typedef struct albuf_t albuf_t;
 typedef struct alchan_t alchan_t;
@@ -31,9 +32,12 @@
 
 static struct {
 	ALuint src, buf;
-	int pcm;
+	int pcm, dec;
+	int len;
 	bool playing;
-	pid_t decoder, reader;
+	bool stop;
+	pid_t decoder;
+	pthread_t reader;
 }track;
 
 static cvar_t s_al_dev = {"s_al_device", "0", true};
@@ -670,7 +674,12 @@
 void
 stepcd(void)
 {
-	alSourcef(track.src, AL_GAIN, bgmvolume.value); ALERR();
+	if(track.stop)
+		stopcd();
+	else if(track.playing){
+		alSourcef(track.src, AL_GAIN, bgmvolume.value);
+		ALERR();
+	}
 }
 
 static ALsizei
@@ -682,9 +691,8 @@
 	USED(aux);
 	for(b = sampledata; numbytes > 0; b += n, numbytes -= n){
 		if((n = read(track.pcm, b, numbytes)) <= 0){
-			close(track.pcm);
-			track.pcm = -1;
-			break;
+			track.stop = true;
+			return 0;
 		}
 	}
 
@@ -691,37 +699,76 @@
 	return b - (byte*)sampledata;
 }
 
+static void *
+trackdecoder(void *f)
+{
+	byte b[65536];
+	ssize_t n;
+	fpos_t off;
+	int left;
+
+	if(fgetpos(f, &off) == 0){
+		left = track.len;
+		for(;;){
+			if((n = fread(b, 1, min(left, (int)sizeof(b)), f)) < 1){
+				if(ferror(f)){
+					perror("fread");
+					break;
+				}
+			}
+			if(write(track.dec, b, n) != n)
+				break;
+			left -= n;
+			if(left < 1){
+				if(!cdloop)
+					break;
+				if(fsetpos(f, &off) != 0){
+					perror("fsetpos");
+					break;
+				}
+				left = track.len;
+			}
+		}
+	}
+	fclose(f);
+	track.stop = true;
+	waitpid(track.decoder, nil, 0);
+
+	return nil;
+}
+
 void
 playcd(int nt, bool loop)
 {
+	int s[2], in[2];
 	pid_t pid;
 	FILE *f;
-	fpos_t off;
-	int len, left, s[2], in[2];
 
 	stopcd();
 	if(qalBufferCallbackSOFT == nil)
 		return;
 
-	if((f = openlmp(va("music/track%02d.ogg", nt), &len)) == nil){
-		if((f = openlmp(va("music/track%02d.mp3", nt), &len)) == nil)
-			f = openlmp(va("music/track%02d.wav", nt), &len);
+	if((f = openlmp(va("music/track%02d.ogg", nt), &track.len)) == nil){
+		if((f = openlmp(va("music/track%02d.mp3", nt), &track.len)) == nil)
+			f = openlmp(va("music/track%02d.wav", nt), &track.len);
 	}
 	if(f == nil)
 		return;
-	if(fgetpos(f, &off) != 0){
+
+	track.decoder = -1;
+	track.reader = -1;
+	if(pipe(s) != 0){
 err:
 		close(track.pcm);
-		fclose(f);
+		close(track.dec);
 		if(track.decoder > 0)
 			waitpid(track.decoder, nil, 0);
 		if(track.reader > 0)
-			waitpid(track.reader, nil, 0);
+			pthread_join(track.reader, nil);
+		else
+			fclose(f);
 		return;
 	}
-
-	if(pipe(s) != 0)
-		goto err;
 	if(pipe(in) != 0){
 		close(s[0]);
 		close(s[1]);
@@ -752,54 +799,21 @@
 	}
 	track.decoder = pid;
 
-	close(s[0]);
-	close(in[1]);
-	track.pcm = in[0];
+	track.dec = s[1]; close(s[0]);
+	track.pcm = in[0]; close(in[1]);
 	cdloop = loop;
 	cdtrk = nt;
 
-	switch((pid = fork())){
-	case 0:
-		close(in[0]);
-		close(0);
-		close(1);
-		left = len;
-		for(;;){
-			byte tmp[32768];
-			ssize_t n;
-			if((n = fread(tmp, 1, min(left, (int)sizeof(tmp)), f)) < 1){
-				if(ferror(f)){
-					perror("fread");
-					break;
-				}
-			}
-			if(write(s[1], tmp, n) != n)
-				break;
-			left -= n;
-			if(left < 1){
-				if(!loop)
-					break;
-				if(fsetpos(f, &off) != 0){
-					perror("fsetpos");
-					break;
-				}
-				left = len;
-			}
-		}
-		close(s[1]);
-		fclose(f);
-		exit(1);
-	case -1:
+	if(pthread_create(&track.reader, nil, trackdecoder, f) != 0)
 		goto err;
-	}
-	track.reader = pid;
 
 	qalBufferCallbackSOFT(track.buf, AL_FORMAT_STEREO16, 44100, trackcb, nil);
 	if(ALERR())
 		goto err;
+	track.playing = true;
+	track.stop = false;
 	alSourcei(track.src, AL_BUFFER, track.buf); ALERR();
 	alSourcePlay(track.src); ALERR();
-	track.playing = true;
 }
 
 void
@@ -828,14 +842,14 @@
 	if(track.playing){
 		alSourceStop(track.src); ALERR();
 		alSourcei(track.src, AL_BUFFER, 0); ALERR();
-		if(track.pcm >= 0)
-			close(track.pcm);
-		waitpid(track.decoder, nil, 0);
-		waitpid(track.reader, nil, 0);
+		close(track.dec);
+		close(track.pcm);
+		pthread_join(track.reader, nil);
 	}
-	track.playing = false;
+	track.dec = -1;
 	track.pcm = -1;
-	track.decoder = track.reader = -1;
+	track.playing = false;
+	track.stop = false;
 }
 
 void