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
|
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include "til_audio.h"
#include "til_audio_context.h"
/* initialize audio via ops using setup, context stored in res_audio_context on success.
* returns -errno on error, 0 on success
* playback is left in a paused state, with an empty queue
*/
int til_audio_open(const til_audio_ops_t *ops, til_setup_t *setup, til_audio_context_t **res_audio_context)
{
til_audio_context_t *c;
int r;
assert(ops);
assert(ops->init);
assert(ops->queue);
assert(ops->n_queued);
assert(setup);
assert(res_audio_context);
r = ops->init(setup, &c);
if (r < 0)
return r;
*res_audio_context = c;
return 0;
}
/* closes audio and frees context,
* callers are expected to use this and not til_audio_context_free().
*/
void til_audio_shutdown(til_audio_context_t *audio_context)
{
assert(audio_context);
assert(audio_context->ops);
if (audio_context->ops->shutdown)
audio_context->ops->shutdown(audio_context);
til_audio_context_free(audio_context);
}
/* install audio hooks to receive notification on events like seek/pause/unpause */
int til_audio_set_hooks(til_audio_context_t *audio_context, til_audio_hooks_t *hooks, void *hooks_context)
{
assert(audio_context);
assert(hooks);
if (audio_context->hooks && audio_context->hooks != hooks)
return -EEXIST;
audio_context->hooks = hooks;
audio_context->hooks_context = hooks_context;
return 0;
}
/* remove audio hooks */
int til_audio_unset_hooks(til_audio_context_t *audio_context, til_audio_hooks_t *hooks, void *hooks_context)
{
assert(audio_context);
assert(hooks);
/* this is kind of silly, but seems potentially useful in the defensive department */
if (audio_context->hooks != hooks ||
audio_context->hooks_context != hooks_context)
return -EINVAL;
audio_context->hooks = NULL;
audio_context->hooks_context = NULL;
return 0;
}
/* seek to an absolute ticks, playback is left in a paused state with an empty queue */
void til_audio_seek(til_audio_context_t *audio_context, unsigned ticks)
{
assert(audio_context);
if (audio_context->ops->pause)
audio_context->ops->pause(audio_context);
if (audio_context->ops->drop)
audio_context->ops->drop(audio_context);
if (audio_context->hooks && audio_context->hooks->seeked)
audio_context->hooks->seeked(audio_context->hooks_context, audio_context, ticks);
}
/* queue n_frames frames to audio_context,
* returns 0 on success, -errno on error
*/
int til_audio_queue(til_audio_context_t *audio_context, int16_t *frames, int n_frames)
{
assert(audio_context);
assert(frames);
assert(n_frames > 0);
return audio_context->ops->queue(audio_context, frames, n_frames);
}
/* query how many frames are currently queued
* returns 0 on success, -errno on error
*/
unsigned til_audio_n_queued(til_audio_context_t *audio_context)
{
assert(audio_context);
return audio_context->ops->n_queued(audio_context);
}
/* pause the underlying audio playback, queue is left as-is, should be idempotent */
void til_audio_pause(til_audio_context_t *audio_context)
{
assert(audio_context);
if (audio_context->ops->pause)
audio_context->ops->pause(audio_context);
if (audio_context->hooks && audio_context->hooks->paused)
audio_context->hooks->paused(audio_context->hooks_context, audio_context);
}
/* unpause the underlying audio playback, queue is left as-is, should be idempotent */
void til_audio_unpause(til_audio_context_t *audio_context)
{
assert(audio_context);
if (audio_context->ops->unpause)
audio_context->ops->unpause(audio_context);
if (audio_context->hooks && audio_context->hooks->unpaused)
audio_context->hooks->unpaused(audio_context->hooks_context, audio_context);
}
|