-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathao.c
153 lines (132 loc) · 3.26 KB
/
ao.c
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
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ao/ao.h>
#include "ao.h"
#include "util.h"
#include "sampleconv.h"
struct ao_state {
ao_device *dev;
struct ao_enc_info *enc_info;
};
struct ao_enc_info {
const char *name;
int bytes, prec;
void (*write_func)(sample_t *, char *, ssize_t);
};
static int ao_open_count = 0;
static struct ao_enc_info encodings[] = {
{ "s16", 2, 16, write_buf_s16 },
{ "u8", 1, 8, write_buf_u8 },
{ "s32", 4, 32, write_buf_s32 },
};
static struct ao_enc_info * ao_get_enc_info(const char *enc)
{
int i;
if (enc == NULL)
return &encodings[0];
for (i = 0; i < LENGTH(encodings); ++i)
if (strcmp(enc, encodings[i].name) == 0)
return &encodings[i];
return NULL;
}
ssize_t ao_read(struct codec *c, sample_t *buf, ssize_t frames)
{
return 0;
}
ssize_t ao_write(struct codec *c, sample_t *buf, ssize_t frames)
{
struct ao_state *state = (struct ao_state *) c->data;
state->enc_info->write_func(buf, (char *) buf, frames * c->channels);
if (ao_play(state->dev, (char *) buf, frames * c->channels * state->enc_info->bytes) == 0) {
LOG(LL_ERROR, "%s: ao: ao_play: write failed\n", dsp_globals.prog_name);
return 0;
}
return frames;
}
ssize_t ao_seek(struct codec *c, ssize_t pos)
{
return -1;
}
ssize_t ao_delay(struct codec *c)
{
return 0;
}
void ao_drop(struct codec *c)
{
/* do nothing */
}
void ao_pause(struct codec *c, int p)
{
/* do nothing */
}
void ao_destroy(struct codec *c)
{
struct ao_state *state = (struct ao_state *) c->data;
ao_close(state->dev);
--ao_open_count;
if (ao_open_count == 0)
ao_shutdown();
free(state);
}
struct codec * ao_codec_init(const char *path, const char *type, const char *enc, int fs, int channels, int endian, int mode)
{
int driver;
struct ao_enc_info *enc_info;
struct ao_sample_format format;
ao_device *dev = NULL;
struct ao_state *state = NULL;
struct codec *c = NULL;
if (ao_open_count == 0)
ao_initialize();
if ((driver = ao_default_driver_id()) == -1) {
LOG(LL_OPEN_ERROR, "%s: ao: error: failed get default driver id\n", dsp_globals.prog_name);
goto fail;
}
if ((enc_info = ao_get_enc_info(enc)) == NULL) {
LOG(LL_ERROR, "%s: ao: error: bad encoding: %s\n", dsp_globals.prog_name, enc);
goto fail;
}
format.bits = enc_info->prec;
format.rate = fs;
format.channels = channels;
format.byte_format = AO_FMT_NATIVE;
format.matrix = NULL;
if ((dev = ao_open_live(driver, &format, NULL)) == NULL) {
LOG(LL_OPEN_ERROR, "%s: ao: error: could not open device\n", dsp_globals.prog_name);
goto fail;
}
state = calloc(1, sizeof(struct ao_state));
state->dev = dev;
state->enc_info = enc_info;
c = calloc(1, sizeof(struct codec));
c->path = path;
c->type = type;
c->enc = enc_info->name;
c->fs = fs;
c->channels = channels;
c->prec = enc_info->prec;
c->can_dither = 1; /* all formats are fixed-point LPCM */
c->interactive = 1;
c->frames = -1;
c->read = ao_read;
c->write = ao_write;
c->seek = ao_seek;
c->delay = ao_delay;
c->drop = ao_drop;
c->pause = ao_pause;
c->destroy = ao_destroy;
c->data = state;
++ao_open_count;
return c;
fail:
if (ao_open_count == 0)
ao_shutdown();
return NULL;
}
void ao_codec_print_encodings(const char *type)
{
int i;
for (i = 0; i < LENGTH(encodings); ++i)
fprintf(stdout, " %s", encodings[i].name);
}