~ft/treason

ref: c1156352ba4eceae2ec875fd06fc94c38c92271f treason/stream_audio.c -rw-r--r-- 1.9 KiB
c1156352 — Sigrid Solveig Haflínudóttir info: mixed up dispdelay and yuv→rgb, fix it 1 year, 1 month ago
                                                                                
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
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "misc.h"
#include "stream.h"

enum {
	Onesec = 2*2*44100, /* 16-bit, stereo */
	Framesz = Onesec/5, /* ⅕ second */
};

static char *progs[] = {
	[FmtAAC] = "/bin/audio/aacdec",
	[FmtMp3] = "/bin/audio/mp3dec",
	[FmtOpus] = "/bin/audio/opusdec",
	[FmtVorbis] = "/bin/audio/oggdec",
	[FmtFlac] = "/bin/audio/flacdec",
};

extern Streamops audops;

int
audopenfd(int fd, Stream *s, int *failed)
{
	int p[2], pid;
	char *prog;
	Dir *d;

	if(fd < 0)
		return -1;
	if(s->fmt >= nelem(progs) || (prog = progs[s->fmt]) == nil){
		werrstr("unsupported audio format %d", s->fmt);
		goto err;
	}

	*failed = 1;
	if((d = dirstat(prog)) == nil){
		werrstr("can't decode, %s isn't available", prog);
		goto err;
	}
	free(d);

	pipe(p);
	if((pid = rfork(RFFDG|RFPROC)) == 0){
		dup(fd, 0); close(fd);
		close(p[0]);
		dup(p[1], 1); close(p[1]);
		if(!debug){
			dup(fd = open("/dev/null", OWRITE), 2);
			close(fd);
		}
		execl(prog, prog, nil);
		sysfatal("exec: %r");
	}
	close(p[1]);
	if(pid < 0){
		close(p[0]);
		goto err;
	}
	close(fd);

	s->type = Saudio;
	s->timebase.denum = 1;
	s->timebase.num = 1;
	s->b = Bfdopen(p[0], OREAD);
	memmove(&s->ops, &audops, sizeof(audops));
	*failed = 0;

	return 0;
err:
	close(fd);
	return -1;
}

static Stream *
audopen(char *path, int *num, int *failed)
{
	Stream *s;

	if((s = calloc(1, sizeof(*s))) == nil){
		*failed = 1;
		return nil;
	}

	*num = 1;
	if(audopenfd(open(path, OREAD), s, failed) != 0){
		free(s);
		s = nil;
	}

	return s;
}

static int
audread(Stream *s, Streamframe *f)
{
	if(s->buf == nil)
		s->buf = malloc(Framesz);
	f->buf = s->buf;
	f->timestamp = s->timestamp;
	if((f->sz = Bread(s->b, f->buf, Framesz)) < 0){ /* eof */
		f->sz = 0;
		return -1;
	}

	f->dt = f->sz * 1000000000ULL / Onesec;
	s->timestamp += f->dt;

	return 0;
}

static void
audclose(Stream *s)
{
	Bterm(s->b);
	free(s->buf);
}

Streamops audops = {
	.open = audopen,
	.read = audread,
	.close = audclose,
};