source: roaraudio/libroar/vio_buffer.c @ 4535:4f08bac78ce0

Last change on this file since 4535:4f08bac78ce0 was 4535:4f08bac78ce0, checked in by phi, 13 years ago

some small buffer vio addition

File size: 8.8 KB
Line 
1//vio_buffer.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38int     roar_vio_open_buffer    (struct roar_vio_calls * calls, struct roar_vio_calls * dst, ssize_t minsize, int use_re) {
39 struct roar_vio_buffer * self;;
40
41 if ( calls == NULL || dst == NULL )
42  return -1;
43
44 if ( (self = roar_mm_malloc(sizeof(struct roar_vio_buffer))) == NULL )
45  return -1;
46
47 memset(self, 0, sizeof(struct roar_vio_buffer));
48
49 self->backend     = dst;
50 self->min_bufsize = minsize;
51 self->use_re      = use_re;
52
53 if ( use_re ) {
54  if ( roar_vio_open_re(&(self->re_vio), dst) == -1 ) {
55   roar_mm_free(self);
56   return -1;
57  }
58 }
59
60 memset(calls, 0, sizeof(struct roar_vio_calls));
61
62 calls->inst     = self;
63 calls->close    = roar_vio_buffer_close;
64 calls->write    = roar_vio_buffer_write;
65 calls->nonblock = roar_vio_buffer_nonblock;
66 calls->ctl      = roar_vio_buffer_ctl;
67 calls->sync     = roar_vio_buffer_sync;
68 calls->lseek    = roar_vio_buffer_lseek;
69
70 return 0;
71}
72
73int     roar_vio_buffer_close   (struct roar_vio_calls * vio) {
74 struct roar_vio_buffer * self = vio->inst;
75 int ret;
76
77 if ( self->buf_old != NULL )
78  roar_buffer_free(self->buf_old);
79
80 if ( self->buf_cur != NULL )
81  roar_buffer_free(self->buf_cur);
82
83 if ( self->use_re ) {
84  ret = roar_vio_close(&(self->re_vio));
85 } else {
86  ret = roar_vio_close(self->backend);
87 }
88
89 roar_mm_free(self);
90
91 return ret;
92}
93
94ssize_t roar_vio_buffer_read    (struct roar_vio_calls * vio, void *buf, size_t count) {
95 struct roar_vio_buffer * self = vio->inst;
96 size_t                   havelen;
97 size_t                   buflen;
98 ssize_t                  ret;
99
100 if ( count == 0 )
101  return 0;
102
103 if ( buf == NULL )
104  return -1;
105
106 if ( self->offset.is_old ) {
107  havelen = (self->len_old + self->len_cur) - self->offset.offset;
108 } else {
109  havelen = self->len_cur - self->offset.offset;
110 }
111
112 if ( havelen == 0 ) {
113  if ( self->use_re ) {
114   ret = roar_vio_read(&(self->re_vio), buf, count);
115  } else {
116   ret = roar_vio_read(self->backend, buf, count);
117  }
118  // TODO...
119  return ret;
120 } else if ( count == havelen ) {
121  if (self->offset.is_old) {
122   buflen = count;
123   if ( roar_buffer_shift_out(&(self->buf_old), buf, &buflen) == -1 )
124    return -1;
125
126   if ( self->buf_old != NULL ) // strange error
127    return buflen;
128
129   buf   += buflen;
130   count -= buflen;
131
132   self->len_old       = 0;
133   self->offset.is_old = 0;
134   self->offset.offset = 0;
135  }
136
137  return -1;
138
139 } else if ( count <  havelen ) {
140 } else if ( count >  havelen ) {
141 }
142
143 return -1;
144}
145
146int     roar_vio_buffer_sync    (struct roar_vio_calls * vio) {
147 struct roar_vio_buffer * self = vio->inst;
148 struct roar_vio_calls  * backend;
149 off_t dst = 0;
150
151 if ( self->use_re ) {
152  backend = &(self->re_vio);
153 } else {
154  backend = self->backend;
155 }
156
157 // bring backend in sync state, if this fails we do not need to continue...
158 if ( self->use_re ) {
159  if ( roar_vio_sync(backend) == -1 )
160   return -1;
161 } else {
162  if ( roar_vio_sync(backend) == -1 )
163   return -1;
164 }
165
166 if ( self->buf_old == NULL && self->buf_cur == NULL )
167  return 0; // we are in sync in case no buffers are currently used.
168
169 if (self->buf_old != NULL && self->buf_cur == NULL ) {
170  // we just finished the segment
171  roar_buffer_free(self->buf_old);
172  return 0;
173 }
174
175 // calc seek pos:
176 if ( self->offset.is_old ) {
177  dst = (self->len_cur + self->len_old) - self->offset.offset;
178 } else {
179  dst = self->len_cur - self->offset.offset;
180 }
181
182 dst = -dst;
183
184 // do the seek:
185 if ( roar_vio_lseek(backend, dst, SEEK_CUR) == (off_t)-1 )
186  return -1;
187
188 // free all internal buffers:
189 if ( self->buf_old != NULL )
190  roar_buffer_free(self->buf_old);
191
192 if ( self->buf_cur != NULL )
193  roar_buffer_free(self->buf_cur);
194
195 self->offset.is_old = 0;
196 self->offset.offset = 0;
197
198 // funally bring the backend in sync state again, to be sure all changes are done.
199 if ( self->use_re ) {
200  if ( roar_vio_sync(backend) == -1 )
201   return -1;
202 } else {
203  if ( roar_vio_sync(backend) == -1 )
204   return -1;
205 }
206
207 return 0;
208}
209
210off_t   roar_vio_buffer_lseek   (struct roar_vio_calls * vio, off_t offset, int whence) {
211 struct roar_vio_buffer * self = vio->inst;
212 size_t newoff;
213 off_t  ret;
214 off_t  invoff;
215
216 // in-memory seeking is only supported for SEEK_CUR:
217 if ( whence == SEEK_CUR ) {
218  if ( offset == 0 ) {
219   return 0;
220  } else if ( offset > 0 ) {
221   newoff = self->offset.offset + offset;
222
223   if ( self->offset.is_old ) {
224    if ( newoff == self->len_old ) {
225     self->offset.is_old = 0;
226     self->offset.offset = 0;
227     self->abspos += offset;
228     return self->abspos;
229    } else if ( newoff < self->len_old ) {
230     self->offset.offset = newoff;
231     self->abspos += offset;
232     return self->abspos;
233    } else if ( newoff > self->len_old ) {
234     if ( newoff < (self->len_old + self->len_cur ) ) {
235      self->offset.is_old = 0;
236      self->offset.offset = offset + self->offset.offset - self->len_old;
237      self->abspos += offset;
238      return self->abspos;
239     }
240    }
241   } else {
242    if ( newoff == self->len_cur ) {
243     roar_buffer_free(self->buf_old);
244     self->buf_old = self->buf_cur;
245     self->buf_cur = NULL;
246     self->offset.offset = 0;
247     self->abspos += offset;
248     return self->abspos;
249    } else if ( newoff < self->len_cur ) {
250     self->offset.offset = newoff;
251     self->abspos += offset;
252     return self->abspos;
253    }
254   }
255  } else {
256   invoff = -offset;
257
258   if ( invoff <= self->offset.offset ) {
259    self->offset.offset = 0;
260    self->abspos -= invoff;
261    return self->abspos;
262   }
263
264   if ( !self->offset.is_old ) {
265    if ( invoff > self->offset.offset ) {
266     if ( invoff <= (self->len_old + self->offset.offset) ) {
267      self->offset.is_old = 1;
268      self->offset.offset = (self->len_old + self->offset.offset) - invoff;
269      self->abspos -= invoff;
270      return self->abspos;
271     }
272    }
273   }
274  }
275 }
276
277 // we need to do a physical seek;
278 // get in sync with current possition, flush all buffers,...
279 if ( roar_vio_buffer_sync(vio) == -1 )
280  return -1;
281
282 // do the seek:
283 if ( self->use_re ) {
284  ret = roar_vio_lseek(&(self->re_vio), offset, whence);
285 } else {
286  ret = roar_vio_lseek(self->backend, offset, whence);
287 }
288
289 if (ret != (off_t)-1)
290  self->abspos = ret;
291
292 return ret;
293}
294
295int     roar_vio_buffer_ctl     (struct roar_vio_calls * vio, int cmd, void * data) {
296 struct roar_vio_buffer * self;
297
298 if (vio == NULL || cmd == -1)
299  return -1;
300
301 ROAR_DBG("roar_vio_buffer_ctl(vio=%p, cmd=0x%.8x, data=%p) = ?", vio, cmd, data);
302
303 self = vio->inst;
304
305 switch (cmd) {
306  case ROAR_VIO_CTL_GET_NAME:
307    if ( data == NULL )
308     return -1;
309
310    *(char**)data = "buffer";
311    return 0;
312   break;
313  case ROAR_VIO_CTL_GET_NEXT:
314    if ( self->use_re ) {
315     *(struct roar_vio_calls **)data = &(self->re_vio);
316    } else {
317     *(struct roar_vio_calls **)data = self->backend;
318    }
319    return 0;
320   break;
321  case ROAR_VIO_CTL_SET_NEXT:
322    if ( self->use_re ) {
323     return roar_vio_ctl(&(self->re_vio), ROAR_VIO_CTL_SET_NEXT, data);
324    } else {
325     self->backend = *(struct roar_vio_calls **)data;
326    }
327    return 0;
328   break;
329 }
330
331 return roar_vio_ctl((struct roar_vio_calls *) vio->inst, cmd, data);
332}
333
334ssize_t roar_vio_buffer_write   (struct roar_vio_calls * vio, void *buf, size_t count) {
335 struct roar_vio_buffer * self = vio->inst;
336
337 if ( self->use_re ) {
338  return roar_vio_write(&(self->re_vio), buf, count);
339 } else {
340  return roar_vio_write(self->backend, buf, count);
341 }
342}
343
344int     roar_vio_buffer_nonblock(struct roar_vio_calls * vio, int state) {
345 struct roar_vio_buffer * self = vio->inst;
346
347 if ( self->use_re ) {
348  return roar_vio_nonblock(&(self->re_vio), state);
349 } else {
350  return roar_vio_nonblock(self->backend, state);
351 }
352}
353
354//ll
Note: See TracBrowser for help on using the repository browser.