OSDN Git Service

conf: usb - correct 'SB Omni Surround 5.1' iec958 device
[android-x86/external-alsa-lib.git] / src / output.c
1 /**
2  * \file output.c
3  * \brief Generic stdio-like output interface
4  * \author Abramo Bagnara <abramo@alsa-project.org>
5  * \date 2000
6  *
7  * Generic stdio-like output interface
8  */
9 /*
10  *  Output object
11  *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
12  *
13  *
14  *   This library is free software; you can redistribute it and/or modify
15  *   it under the terms of the GNU Lesser General Public License as
16  *   published by the Free Software Foundation; either version 2.1 of
17  *   the License, or (at your option) any later version.
18  *
19  *   This program is distributed in the hope that it will be useful,
20  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *   GNU Lesser General Public License for more details.
23  *
24  *   You should have received a copy of the GNU Lesser General Public
25  *   License along with this library; if not, write to the Free Software
26  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
27  *
28  */
29
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include "local.h"
35
36 #ifndef DOC_HIDDEN
37 typedef struct _snd_output_ops {
38         int (*close)(snd_output_t *output);
39         int (*print)(snd_output_t *output, const char *format, va_list args);
40         int (*puts)(snd_output_t *output, const char *str);
41         int (*putch)(snd_output_t *output, int c);
42         int (*flush)(snd_output_t *output);
43 } snd_output_ops_t;
44
45 struct _snd_output {
46         snd_output_type_t type;
47         const snd_output_ops_t *ops;
48         void *private_data;
49 };
50 #endif
51
52 /**
53  * \brief Closes an output handle.
54  * \param output The output handle to be closed.
55  * \return Zero if successful, otherwise a negative error code.
56  */
57 int snd_output_close(snd_output_t *output)
58 {
59         int err = output->ops->close(output);
60         free(output);
61         return err;
62 }
63
64 /**
65  * \brief Writes formatted output (like \c fprintf(3)) to an output handle.
66  * \param output The output handle.
67  * \param format Format string in \c fprintf format.
68  * \param ... Other \c fprintf arguments.
69  * \return The number of characters written, or a negative error code.
70  */
71 int snd_output_printf(snd_output_t *output, const char *format, ...)
72 {
73         int result;
74         va_list args;
75         va_start(args, format);
76         result = output->ops->print(output, format, args);
77         va_end(args);
78         return result;
79 }
80
81 /**
82  * \brief Writes formatted output (like \c fprintf(3)) to an output handle.
83  * \param output The output handle.
84  * \param format Format string in \c fprintf format.
85  * \param args Other \c fprintf arguments.
86  * \return The number of characters written, or a negative error code.
87  */
88 int snd_output_vprintf(snd_output_t *output, const char *format, va_list args)
89 {
90         return output->ops->print(output, format, args);
91 }
92
93 /**
94  * \brief Writes a string to an output handle (like \c fputs(3)).
95  * \param output The output handle.
96  * \param str Pointer to the string.
97  * \return Zero if successful, otherwise a negative error code or \c EOF.
98  */
99 int snd_output_puts(snd_output_t *output, const char *str)
100 {
101         return output->ops->puts(output, str);
102 }
103                         
104 /**
105  * \brief Writes a character to an output handle (like \c putc(3)).
106  * \param output The output handle.
107  * \param c The character.
108  * \return Zero if successful, otherwise a negative error code or \c EOF.
109  */
110 int snd_output_putc(snd_output_t *output, int c)
111 {
112         return output->ops->putch(output, c);
113 }
114
115 /**
116  * \brief Flushes an output handle (like fflush(3)).
117  * \param output The output handle.
118  * \return Zero if successful, otherwise \c EOF.
119  *
120  * If the underlying destination is a stdio stream, this function calls
121  * \c fflush. If the underlying destination is a memory buffer, the write
122  * position is reset to the beginning of the buffer. \c =:-o
123  */
124 int snd_output_flush(snd_output_t *output)
125 {
126         return output->ops->flush(output);
127 }
128
129 #ifndef DOC_HIDDEN
130 typedef struct _snd_output_stdio {
131         int close;
132         FILE *fp;
133 } snd_output_stdio_t;
134
135 static int snd_output_stdio_close(snd_output_t *output)
136 {
137         snd_output_stdio_t *stdio = output->private_data;
138         if (stdio->close)
139                 fclose(stdio->fp);
140         free(stdio);
141         return 0;
142 }
143
144 static int snd_output_stdio_print(snd_output_t *output, const char *format, va_list args)
145 {
146         snd_output_stdio_t *stdio = output->private_data;
147         return vfprintf(stdio->fp, format, args);
148 }
149
150 static int snd_output_stdio_puts(snd_output_t *output, const char *str)
151 {
152         snd_output_stdio_t *stdio = output->private_data;
153         return fputs(str, stdio->fp);
154 }
155                         
156 static int snd_output_stdio_putc(snd_output_t *output, int c)
157 {
158         snd_output_stdio_t *stdio = output->private_data;
159         return putc(c, stdio->fp);
160 }
161
162 static int snd_output_stdio_flush(snd_output_t *output)
163 {
164         snd_output_stdio_t *stdio = output->private_data;
165         return fflush(stdio->fp);
166 }
167
168 static const snd_output_ops_t snd_output_stdio_ops = {
169         .close          = snd_output_stdio_close,
170         .print          = snd_output_stdio_print,
171         .puts           = snd_output_stdio_puts,
172         .putch          = snd_output_stdio_putc,
173         .flush          = snd_output_stdio_flush,
174 };
175
176 #endif
177
178 /**
179  * \brief Creates a new output object using an existing stdio \c FILE pointer.
180  * \param outputp The function puts the pointer to the new output object
181  *                at the address specified by \p outputp.
182  * \param fp The \c FILE pointer to write to. Characters are written
183  *           to the file starting at the current file position.
184  * \param _close Close flag. Set this to 1 if #snd_output_close should close
185  *              \p fp by calling \c fclose.
186  * \return Zero if successful, otherwise a negative error code.
187  */
188 int snd_output_stdio_attach(snd_output_t **outputp, FILE *fp, int _close)
189 {
190         snd_output_t *output;
191         snd_output_stdio_t *stdio;
192         assert(outputp && fp);
193         stdio = calloc(1, sizeof(*stdio));
194         if (!stdio)
195                 return -ENOMEM;
196         output = calloc(1, sizeof(*output));
197         if (!output) {
198                 free(stdio);
199                 return -ENOMEM;
200         }
201         stdio->fp = fp;
202         stdio->close = _close;
203         output->type = SND_OUTPUT_STDIO;
204         output->ops = &snd_output_stdio_ops;
205         output->private_data = stdio;
206         *outputp = output;
207         return 0;
208 }
209         
210 /**
211  * \brief Creates a new output object writing to a file.
212  * \param outputp The function puts the pointer to the new output object
213  *                at the address specified by \p outputp.
214  * \param file The name of the file to open.
215  * \param mode The open mode, like \c fopen(3).
216  * \return Zero if successful, otherwise a negative error code.
217  */
218 int snd_output_stdio_open(snd_output_t **outputp, const char *file, const char *mode)
219 {
220         int err;
221         FILE *fp = fopen(file, mode);
222         if (!fp) {
223                 //SYSERR("fopen");
224                 return -errno;
225         }
226         err = snd_output_stdio_attach(outputp, fp, 1);
227         if (err < 0)
228                 fclose(fp);
229         return err;
230 }
231
232 #ifndef DOC_HIDDEN
233
234 typedef struct _snd_output_buffer {
235         unsigned char *buf;
236         size_t alloc;
237         size_t size;
238 } snd_output_buffer_t;
239
240 static int snd_output_buffer_close(snd_output_t *output)
241 {
242         snd_output_buffer_t *buffer = output->private_data;
243         free(buffer->buf);
244         free(buffer);
245         return 0;
246 }
247
248 static int snd_output_buffer_need(snd_output_t *output, size_t size)
249 {
250         snd_output_buffer_t *buffer = output->private_data;
251         size_t _free = buffer->alloc - buffer->size;
252         size_t alloc;
253         unsigned char *buf;
254
255         /* use 'size++' to allow to add the '\0' string terminator */
256         /* without reallocation */
257         size++;
258         if (_free >= size)
259                 return _free;
260         if (buffer->alloc == 0)
261                 alloc = 256;
262         else
263                 alloc = buffer->alloc;
264         while (alloc < buffer->size + size)
265                 alloc *= 2;
266         buf = realloc(buffer->buf, alloc);
267         if (!buf)
268                 return -ENOMEM;
269         buffer->buf = buf;
270         buffer->alloc = alloc;
271         return buffer->alloc - buffer->size;
272 }
273
274 static int snd_output_buffer_print(snd_output_t *output, const char *format, va_list args)
275 {
276         snd_output_buffer_t *buffer = output->private_data;
277         size_t size = 256;
278         int result;
279         result = snd_output_buffer_need(output, size);
280         if (result < 0)
281                 return result;
282         result = vsnprintf((char *)buffer->buf + buffer->size, size, format, args);
283         assert(result >= 0);
284         if ((size_t)result <= size) {
285                 buffer->size += result;
286                 return result;
287         }
288         size = result;
289         result = snd_output_buffer_need(output, size);
290         if (result < 0)
291                 return result;
292         result = vsnprintf((char *)buffer->buf + buffer->size, result, format, args);
293         assert(result == (int)size);
294         buffer->size += result;
295         return result;
296 }
297
298 static int snd_output_buffer_puts(snd_output_t *output, const char *str)
299 {
300         snd_output_buffer_t *buffer = output->private_data;
301         size_t size = strlen(str);
302         int err;
303         err = snd_output_buffer_need(output, size);
304         if (err < 0)
305                 return err;
306         memcpy(buffer->buf + buffer->size, str, size);
307         buffer->size += size;
308         return size;
309 }
310                         
311 static int snd_output_buffer_putc(snd_output_t *output, int c)
312 {
313         snd_output_buffer_t *buffer = output->private_data;
314         int err;
315         err = snd_output_buffer_need(output, 1);
316         if (err < 0)
317                 return err;
318         buffer->buf[buffer->size++] = c;
319         return 0;
320 }
321
322 static int snd_output_buffer_flush(snd_output_t *output ATTRIBUTE_UNUSED)
323 {
324         snd_output_buffer_t *buffer = output->private_data;
325         buffer->size = 0;
326         return 0;
327 }
328
329 static const snd_output_ops_t snd_output_buffer_ops = {
330         .close          = snd_output_buffer_close,
331         .print          = snd_output_buffer_print,
332         .puts           = snd_output_buffer_puts,
333         .putch          = snd_output_buffer_putc,
334         .flush          = snd_output_buffer_flush,
335 };
336 #endif
337
338 /**
339  * \brief Returns the address of the buffer of a #SND_OUTPUT_BUFFER output handle.
340  * \param output The output handle.
341  * \param buf The functions puts the current address of the buffer at the
342  *            address specified by \p buf.
343  * \return The current size of valid data in the buffer.
344  *
345  * The address of the buffer may become invalid when output functions or
346  * #snd_output_close are called.
347  */
348 size_t snd_output_buffer_string(snd_output_t *output, char **buf)
349 {
350         snd_output_buffer_t *buffer = output->private_data;
351         *buf = (char *)buffer->buf;
352         return buffer->size;
353 }
354
355 /**
356  * \brief Returns the address of the buffer of a #SND_OUTPUT_BUFFER output handle.
357  * \param output The output handle.
358  * \param buf The functions puts the current address of the buffer at the
359  *            address specified by \p buf.
360  * \return The current size of valid data in the buffer.
361  *
362  * The internal buffer is empty after this call. The caller has the responsibility
363  * to clean the buffer using the free() call.
364  */
365 size_t snd_output_buffer_steal(snd_output_t *output, char **buf)
366 {
367         snd_output_buffer_t *buffer = output->private_data;
368         size_t size;
369         *buf = (char *)buffer->buf;
370         size = buffer->size;
371         buffer->buf = NULL;
372         buffer->alloc = 0;
373         buffer->size = 0;
374         return size;
375 }
376
377 /**
378  * \brief Creates a new output object with an auto-extending memory buffer.
379  * \param outputp The function puts the pointer to the new output object
380  *                at the address specified by \p outputp.
381  * \return Zero if successful, otherwise a negative error code.
382  */
383 int snd_output_buffer_open(snd_output_t **outputp)
384 {
385         snd_output_t *output;
386         snd_output_buffer_t *buffer;
387         assert(outputp);
388         buffer = calloc(1, sizeof(*buffer));
389         if (!buffer)
390                 return -ENOMEM;
391         output = calloc(1, sizeof(*output));
392         if (!output) {
393                 free(buffer);
394                 return -ENOMEM;
395         }
396         buffer->buf = NULL;
397         buffer->alloc = 0;
398         buffer->size = 0;
399         output->type = SND_OUTPUT_BUFFER;
400         output->ops = &snd_output_buffer_ops;
401         output->private_data = buffer;
402         *outputp = output;
403         return 0;
404 }