summaryrefslogtreecommitdiff
path: root/src/mem_audio.c
blob: b8d51dfc833c3a702504f8c2d27c54896e003bc6 (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
#include <assert.h>
#include <errno.h>
#include <stdlib.h>

#include "til.h"
#include "til_audio.h"
#include "til_audio_context.h"
#include "til_settings.h"
#include "til_setup.h"

/* "mem" audio backend */

typedef struct mem_audio_setup_t {
	til_setup_t	til_setup;
} mem_audio_setup_t;

typedef struct mem_audio_t {
	til_audio_context_t	til_audio_context;

	unsigned		n_queued;
	unsigned		n_queued_start_ticks;
	unsigned		paused:1;
} mem_audio_t;


static int mem_audio_init(til_setup_t *setup, til_audio_context_t **res_context);
static int mem_audio_queue(til_audio_context_t *context, int16_t *frames, int n_frames);;
static unsigned mem_audio_n_queued(til_audio_context_t *context);
static void mem_audio_drop(til_audio_context_t *context);
static void mem_audio_pause(til_audio_context_t *context);
static void mem_audio_unpause(til_audio_context_t *context);
static int mem_audio_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup);


til_audio_ops_t mem_audio_ops = {
	.init = mem_audio_init,
	.drop = mem_audio_drop,
	.pause = mem_audio_pause,
	.unpause = mem_audio_unpause,
	.queue = mem_audio_queue,
	.n_queued = mem_audio_n_queued,
	.setup = mem_audio_setup,
};


/* this simulates an audio timer grinding through the queued frames when unpaused,
 * returns the remaining n_queued (if any) for convenience, but it's also maintained
 * at c->n_queued.
 */
static unsigned mem_refresh_n_queued(mem_audio_t *c)
{
	if (!c->paused && c->n_queued) {
		unsigned	now = til_ticks_now();
		unsigned	n_played = ((float)(now - c->n_queued_start_ticks) * 44.1f);

		c->n_queued -= MIN(c->n_queued, n_played);
	}

	return c->n_queued;
}


static int mem_audio_init(til_setup_t *setup, til_audio_context_t **res_context)
{
	mem_audio_t	*c;

	assert(setup);
	assert(res_context);

	c = til_audio_context_new(&mem_audio_ops, sizeof(mem_audio_t), setup);
	if (!c)
		return -ENOMEM;

	c->paused = 1;
	*res_context = &c->til_audio_context;

	return 0;
}


static void mem_audio_drop(til_audio_context_t *context)
{
	mem_audio_t	*c = (mem_audio_t *)context;

	c->n_queued = 0;
}


static void mem_audio_pause(til_audio_context_t *context)
{
	mem_audio_t	*c = (mem_audio_t *)context;

	if (!c->paused) {
		mem_refresh_n_queued(c);
		c->paused = 1;
	}
}


static void mem_audio_unpause(til_audio_context_t *context)
{
	mem_audio_t	*c = (mem_audio_t *)context;

	if (c->paused) {
		c->paused = 0;
		c->n_queued_start_ticks = til_ticks_now();
	}
}


static int mem_audio_queue(til_audio_context_t *context, int16_t *frames, int n_frames)
{
	mem_audio_t	*c = (mem_audio_t *)context;

	mem_refresh_n_queued(c);
	c->n_queued += n_frames;

	return 0;
}


static unsigned mem_audio_n_queued(til_audio_context_t *context)
{
	mem_audio_t	*c = (mem_audio_t *)context;

	return mem_refresh_n_queued(c);
}


static int mem_audio_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup)
{
	if (res_setup) {
		mem_audio_setup_t	*setup;

		setup = til_setup_new(settings, sizeof(*setup), NULL, &mem_audio_ops);
		if (!setup)
			return -ENOMEM;

		*res_setup = &setup->til_setup;
	}

	return 0;
}
© All Rights Reserved