Ticket #76: ao_roar.2.c

File ao_roar.2.c, 6.9 KB (added by themaister, 13 years ago)

Some fixes for ao_roar.c

Line 
1//ao_roar.c:
2/*
3 * ao_roar - RoarAudio audio output driver for MPlayer
4 *
5 * copyright (c) 2002 Juergen Keil <jk@tools.de>
6 * copyright (c) 2008-2010 Philipp 'ph3-der-loewe' Schafft
7 * copyright (c) 2010 Hans-Kristian 'maister' Arntzen
8 *
9 * This file is part of MPlayer.
10 *
11 * MPlayer is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * MPlayer is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26
27#include "config.h"
28
29#include <stdlib.h>
30#include <string.h>
31
32#include "libavutil/common.h"
33#include "mpbswap.h"
34#include "subopt-helper.h"
35#include "libaf/af_format.h"
36#include "libaf/reorder_ch.h"
37#include "audio_out.h"
38#include "audio_out_internal.h"
39#include "mp_msg.h"
40#include "help_mp.h"
41#include <assert.h>
42
43#include <roaraudio.h>
44
45
46static const ao_info_t info =
47{
48   "RoarAudio audio output",
49   "roar",
50   "Philipp 'ph3-der-loewe' Schafft <lion@lion.leolix.org>, Hans-Kristian Arntzen",
51   ""
52};
53
54LIBAO_EXTERN(roar)
55
56static char *host = NULL;
57static char *role = NULL;
58static roar_vs_t * vss = NULL;
59static int err = ROAR_ERROR_NONE;
60static const size_t g_buffer_size = (1 << 15);
61
62static int format2codecbits (int format, int * codec_p, int * bits_p) {
63   int codec = -1;
64   int bits  = -1;
65
66   if ( (format & AF_FORMAT_POINT_MASK) != AF_FORMAT_I && (format & AF_FORMAT_POINT_MASK) != 0 )
67      return -1;
68
69   switch (format & (AF_FORMAT_BITS_MASK|AF_FORMAT_SPECIAL_MASK)) {
70    case AF_FORMAT_8BIT:
71    case AF_FORMAT_A_LAW:
72    case AF_FORMAT_MU_LAW:
73      bits = 8;
74     break;
75    case AF_FORMAT_16BIT: bits = 16; break;
76    case AF_FORMAT_24BIT: bits = 24; break;
77    case AF_FORMAT_32BIT: bits = 32; break;
78    case AF_FORMAT_40BIT: bits = 40; break;
79    case AF_FORMAT_48BIT: bits = 48; break;
80    default:
81      return -1;
82   }
83
84   switch (format & AF_FORMAT_SPECIAL_MASK) {
85    case 0:
86      codec = 0;
87     break;
88    case AF_FORMAT_A_LAW:
89      codec = ROAR_CODEC_ALAW;
90     break;
91    case AF_FORMAT_MU_LAW:
92      codec = ROAR_CODEC_MULAW;
93     break;
94    default:
95      return -1;
96   }
97
98   if ( codec == 0 ) {
99    codec = ROAR_CODEC_PCM;
100
101    switch (format & AF_FORMAT_END_MASK) {
102     case AF_FORMAT_BE: codec |= ROAR_CODEC_BE; break;
103     case AF_FORMAT_LE: codec |= ROAR_CODEC_LE; break;
104     default:
105       return -1;
106    }
107    switch (format & AF_FORMAT_SIGN_MASK) {
108     case AF_FORMAT_SI: codec |= 0 /* no specal const here */; break;
109     case AF_FORMAT_US: codec |= ROAR_CODEC_UNSIGNED; break;
110     default:
111       return -1;
112    }
113   }
114
115   if ( codec_p != NULL )
116      *codec_p = codec;
117   if ( bits_p != NULL )
118      *bits_p  = bits;
119
120   return 0;
121}
122
123static int control(int cmd, void *arg)
124{
125    ao_control_vol_t * vol;
126
127    switch (cmd) {
128    case AOCONTROL_QUERY_FORMAT:
129      if ( format2codecbits((int)arg, NULL, NULL) == 0 )
130        return CONTROL_TRUE;
131      return CONTROL_FALSE;
132    case AOCONTROL_GET_VOLUME:
133      vol = arg;
134      if ( roar_vs_volume_get(vss, &(vol->left), &(vol->right), &err) == -1 )
135         return CONTROL_ERROR;
136
137      vol->left  *= 100.;
138      vol->right *= 100.;
139
140      return CONTROL_OK;
141    case AOCONTROL_SET_VOLUME:
142      vol = arg;
143
144      if ( roar_vs_volume_stereo(vss, vol->left / 100., vol->right / 100., &err) == -1 )
145         return CONTROL_ERROR;
146      return CONTROL_OK;
147
148    default:
149      return CONTROL_UNKNOWN;
150    }
151}
152
153static int init(int rate, int channels, int format, int flags)
154{
155   int bufsize = g_buffer_size;
156   int codec;
157   int bits;
158   int roleid = ROAR_ROLE_UNKNOWN;
159   const opt_t subopts[] = {
160      {"host", OPT_ARG_MSTRZ, &host, NULL},
161      {"role", OPT_ARG_MSTRZ, &role, NULL},
162      {NULL}
163   };
164
165   if ( host != NULL )
166      free(host);
167
168   if ( role != NULL )
169      free(role);
170
171   // Parses commandline
172   if (subopt_parse(ao_subdevice, subopts) != 0) {
173      return 0;
174   }
175
176
177   if ( role != NULL ) {
178      roleid = roar_str2role(role);
179      if ( roleid == ROAR_ROLE_UNKNOWN )
180         return 0;
181   }
182
183   ao_data.format = format;
184
185   if ( format2codecbits(format, &codec, &bits) == -1 ) {
186      ao_data.format = AF_FORMAT_S16_LE;
187      codec = ROAR_CODEC_PCM_S_LE;
188      bits  = 16;
189   }
190
191   vss = roar_vs_new_simple(host, "MPlayer", rate, channels, codec, bits, ROAR_DIR_PLAY, &err);
192
193   if ( vss == NULL )
194      return 0;
195
196   if ( roleid != ROAR_ROLE_UNKNOWN ) {
197      if ( roar_vs_role(vss, roleid, &err) == -1 ) {
198         roar_vs_close(vss, ROAR_VS_TRUE, NULL);
199         vss = NULL;
200         return 0;
201      }
202   }
203
204   if ( roar_vs_buffer(vss, bufsize, &err) == -1 ) {
205      roar_vs_close(vss, ROAR_VS_TRUE, NULL);
206      vss = NULL;
207      return 0;
208   }
209
210   // We need non-blocking operation here due to MPlayers buffering scheme.
211   if ( roar_vs_blocking(vss, ROAR_VS_FALSE, &err) == -1 ) {
212      roar_vs_close(vss, ROAR_VS_TRUE, NULL);
213      vss = NULL;
214      return 0;
215   }
216
217   ao_data.channels = channels;
218   ao_data.samplerate = rate;
219   ao_data.bps = (channels*rate*bits)/8;
220
221   ao_data.outburst = bufsize >> 5;
222   ao_data.buffersize = bufsize;
223   
224   return 1;
225}
226
227static void uninit(int n)
228{
229   roar_vs_close(vss, ROAR_VS_FALSE, &err);
230   vss = NULL;
231}
232
233// Reset our buffer. :)
234static void reset(void)
235{
236   roar_vs_reset_buffer(vss, ROAR_VS_TRUE, ROAR_VS_TRUE, &err);
237}
238
239static void audio_pause(void)
240{
241   roar_vs_pause(vss, ROAR_VS_TRUE, &err);
242}
243
244static void audio_resume(void)
245{
246   roar_vs_pause(vss, ROAR_VS_FALSE, &err);
247}
248
249// Returns space we are guaranteed to be able to write in a non-blocking fashion.
250static int get_space(void)
251{
252   // Temporary hack while waiting for a proper non-blocking roar_vs_iterate.
253   // roar_vs_iterate will keep returning 1 even if non-blocking write couldn't write anything.
254   int size;
255   int cnt = 0;
256   while (roar_vs_iterate(vss, ROAR_VS_NOWAIT, &err) > 0 && ++cnt < 16);
257
258   size = roar_vs_get_avail_write(vss, &err);
259
260   // Round down to nearest multiple of outburst.
261   size &= ~(ao_data.outburst - 1);
262   return size;
263}
264
265static int play(void* data, int len, int flags)
266{
267   // MPlayer doesn't seem to care about errors here, so just assume everything works out.
268   roar_vs_write(vss, data, len, &err);
269   return len;
270}
271
272static float roar_latency(void)
273{
274   float latency = roar_vs_latency(vss, ROAR_VS_BACKEND_FIRST, &err) / 1000000.0;
275   return latency;
276}
277
278// Return audio latency in seconds.
279static float get_delay(void)
280{
281   // Same hack
282   int cnt = 0;
283   while (roar_vs_iterate(vss, ROAR_VS_NOWAIT, &err) > 0 && ++cnt < 16);
284
285   return roar_latency();
286}
287
288