1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1992-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <stdlib.h>
30 #include <memory.h>
31 #include "../include/AudioDebug.h"
32 #include "../include/AudioBuffer.h"
33 #include "../include/zmalloc.h"
34
35 // class AudioBuffer methods
36
37 // Constructor with optional hdr, size, and name arguments
38 AudioBuffer::
AudioBuffer(double len,const char * local_name)39 AudioBuffer(
40 double len, // buffer length, in seconds
41 const char *local_name): // name
42 AudioStream(local_name), buflen(len), bufaddr(0), zflag(0), bufsize(0)
43 {
44 }
45
46 // Destructor
47 AudioBuffer::
~AudioBuffer()48 ~AudioBuffer()
49 {
50 (void) SetSize(0.); // deallocate the buffer
51 }
52
53 // XXX - the following functions are good candidates for inlining
54
55 // Return TRUE if the stream is 'open'
56 Boolean AudioBuffer::
opened() const57 opened() const
58 {
59 // A buffer is open if it is allocated and has a valid header
60 return (hdrset() && (GetAddress() != 0));
61 }
62
63 #define MIN_ZBUFFER (8192 * 10) // only for large buffers
64
65 // Allocate buffer. Size and header must be set.
66 AudioError AudioBuffer::
alloc()67 alloc()
68 {
69 long size;
70 size_t cnt;
71 unsigned int ncpy;
72 void* tmpbuf;
73
74 // this is going to be the size we're setting the buffer
75 // to (buflen field). it's set by calling SetSize().
76 size = GetHeader().Time_to_Bytes(GetSize());
77
78 // this is actual current size, in bytes, of the allocated
79 // buffer (the bufsize field).
80 cnt = GetByteCount();
81
82 AUDIO_DEBUG((5, "%d: AudioBuffer::alloc - change from %d to %d bytes\n",
83 getid(), cnt, size));
84
85 bufsize = 0;
86
87 if (size == 0) {
88 // Zero size deletes the buffer
89 if (bufaddr != 0) {
90 if (zflag != 0) {
91 AUDIO_DEBUG((5,
92 "%d: AudioBuffer::alloc - zfree mmapped buffer\n",
93 getid()));
94 (void) zfree((char *)bufaddr);
95 } else {
96 AUDIO_DEBUG((5,
97 "%d: AudioBuffer::alloc - free malloc'd buffer\n",
98 getid()));
99 (void) free((char *)bufaddr);
100 }
101 zflag = 0;
102 }
103 bufaddr = 0;
104
105 } else if (size < 0) {
106 // Ridiculous size
107 AUDIO_DEBUG((5, "%d: AudioBuffer::alloc - bad size\n",
108 getid()));
109 return (RaiseError(AUDIO_ERR_BADARG));
110
111 } else if (bufaddr == 0) {
112 // Allocate a new buffer
113 if (size > MIN_ZBUFFER) {
114 AUDIO_DEBUG((5,
115 "%d: AudioBuffer::alloc - zmalloc new buffer\n",
116 getid()));
117 bufaddr = (void*) zmalloc((unsigned int)size);
118 zflag = 1;
119 } else {
120 AUDIO_DEBUG((5,
121 "%d: AudioBuffer::alloc - malloc new buffer\n",
122 getid()));
123 bufaddr = (void*) malloc((unsigned int)size);
124 zflag = 0;
125 }
126 if (bufaddr == 0) {
127 AUDIO_DEBUG((5,
128 "%d: AudioBuffer::alloc - buffer alloc failed\n",
129 getid()));
130 return (RaiseError(AUDIO_UNIXERROR));
131 }
132 } else {
133 // A buffer was already allocated.
134 // Change its size, preserving as much data as possible.
135 if ((cnt <= MIN_ZBUFFER) && (size <= MIN_ZBUFFER) &&
136 (zflag == 0)) {
137 AUDIO_DEBUG((5,
138 "%d: AudioBuffer::alloc - realloc to change size\n",
139 getid()));
140 bufaddr = (void*)
141 realloc((char *)bufaddr, (unsigned int)size);
142 } else {
143 AUDIO_DEBUG((5,
144 "%d: AudioBuffer::alloc - zmalloc new buffer\n",
145 getid()));
146 tmpbuf = bufaddr;
147 bufaddr = (void*) zmalloc((unsigned int)size);
148
149 // copy over as much of the old data as will fit
150 if (bufaddr != 0) {
151 ncpy = (cnt < size) ? (unsigned int)cnt :
152 (unsigned int)size;
153
154 AUDIO_DEBUG((5,
155 "%d: AudioBuffer::alloc - trasnfer %d bytes\n",
156 getid(), ncpy));
157 (void) memcpy(bufaddr, tmpbuf, ncpy);
158 }
159 if ((cnt > MIN_ZBUFFER) && (zflag != 0)) {
160 AUDIO_DEBUG((5,
161 "%d: AudioBuffer::alloc - zfree old buffer\n",
162 getid()));
163 (void) zfree((char *)tmpbuf);
164 } else {
165 AUDIO_DEBUG((5,
166 "%d: AudioBuffer::alloc - free old buffer\n",
167 getid()));
168 (void) free((char *)tmpbuf);
169 }
170 zflag = 1;
171 }
172 if (bufaddr == 0) {
173 return (RaiseError(AUDIO_UNIXERROR));
174 }
175 }
176 bufsize = (size_t)size;
177 return (AUDIO_SUCCESS);
178 }
179
180
181 // Return the buffer address
182 void* AudioBuffer::
GetAddress() const183 GetAddress() const
184 {
185 return (GetAddress(0.));
186 }
187
188 // Return the buffer address at a given time offset
189 // Returns NULL if no buffer, or the position is not within the buffer.
190 void* AudioBuffer::
GetAddress(Double pos) const191 GetAddress(
192 Double pos) const
193 {
194 char *addr;
195 AudioHdr hdr_local;
196 AudioHdr(AudioBuffer::*hfunc)()const;
197
198 addr = (char *)bufaddr;
199 if ((addr == 0) || (pos < 0.) || (pos >= buflen))
200 return (NULL);
201
202 // If no offset, it's ok if the header hasn't been set yet
203 if (pos == 0.)
204 return ((void*) addr);
205
206 // Get the header and make sure it's valid
207 // This convoluted hfunc works around non-const function problems
208 hfunc = (AudioHdr(AudioBuffer::*)() const)&AudioBuffer::GetHeader;
209 hdr_local = (this->*hfunc)();
210 if (hdr_local.Validate())
211 return (NULL);
212 addr += hdr_local.Time_to_Bytes(pos);
213
214 // One more validation, to be paranoid before handing out this address
215 if (addr >= ((char *)bufaddr + bufsize))
216 return (NULL);
217 return ((void*) addr);
218 }
219
220 // Return the buffer size, in bytes
221 // (as opposed to 'length' which indicates how much data is in the buffer)
222 size_t AudioBuffer::
GetByteCount() const223 GetByteCount() const
224 {
225 return (bufsize);
226 }
227
228 // Return the buffer size, in seconds
229 // (as opposed to 'length' which indicates how much data is in the buffer)
230 Double AudioBuffer::
GetSize() const231 GetSize() const
232 {
233 return (buflen);
234 }
235
236 // Set the buffer size, allocating the buffer as necessary
237 AudioError AudioBuffer::
SetSize(Double len)238 SetSize(
239 Double len) // new size, in seconds
240 {
241 // If no change in size, do nothing
242 if (len == buflen)
243 return (AUDIO_SUCCESS);
244
245 // If header not set, store the size for later
246 buflen = len;
247 if (!hdrset()) {
248 return (AUDIO_SUCCESS);
249 }
250
251 // If shrinking buffer, note this
252 if (buflen < GetLength())
253 SetLength(buflen);
254 return (alloc());
255 }
256
257 // Set the data header
258 // If no buffer allocated, allocate one now (if size is set).
259 // If buffer allocated, fiddle the sizes to account for new header type.
260 AudioError AudioBuffer::
SetHeader(const AudioHdr & h)261 SetHeader(
262 const AudioHdr& h) // header to copy
263 {
264 AudioError err;
265
266 // Validate, then update the header
267 err = h.Validate();
268 if (err)
269 return (RaiseError(err));
270 (void) AudioStream::updateheader(h);
271
272 // If no size set, done for now
273 if (buflen == 0.)
274 return (AUDIO_SUCCESS);
275
276 // If no buffer allocated, allocate one now
277 if (GetAddress() == 0)
278 return (alloc());
279
280 // If buffer allocated, change size to match new header
281 buflen = h.Bytes_to_Time(GetByteCount());
282 return (AUDIO_SUCCESS);
283 }
284
285 // Set the buffer length (ie, the amount of data written to the buffer)
286 void AudioBuffer::
SetLength(Double len)287 SetLength(
288 Double len) // new length
289 {
290 if (!hdrset() || (len < 0.)) // no-op if not ready
291 return;
292 if (!opened() && (len > 0.))
293 return;
294
295 if (Undefined(len) || (len > GetSize())) {
296 // Limit to the size of the buffer
297 setlength(GetSize());
298 } else {
299 setlength(len);
300 }
301 }
302
303 // Copy data from local buffer into specified buffer.
304 // No data format translation takes place.
305 // The object's read position is not updated.
306 AudioError AudioBuffer::
ReadData(void * buf,size_t & len,Double & pos)307 ReadData(
308 void* buf, // destination buffer address
309 size_t& len, // buffer length (updated)
310 Double& pos) // start position (updated)
311 {
312 off_t resid;
313 off_t cnt;
314 off_t offset;
315 AudioError err;
316
317 // Copy length, zero return value
318 cnt = (off_t)len;
319 len = 0;
320
321 // Cannot read if buffer or header not valid
322 if (!opened())
323 return (RaiseError(AUDIO_ERR_NOEFFECT));
324
325 // Position must be valid
326 if ((pos < 0.) || (cnt < 0))
327 return (RaiseError(AUDIO_ERR_BADARG));
328
329 // If the starting offset is at or beyond EOF, return eof flag
330 if (pos >= GetLength()) {
331 err = AUDIO_EOF;
332 err.sys = AUDIO_COPY_INPUT_EOF;
333 return (err);
334 }
335
336 // Limit transfer to remaining room in buffer
337 offset = GetHeader().Time_to_Bytes(pos);
338 resid = GetHeader().Time_to_Bytes(GetLength()) - offset;
339 if (resid <= 0) {
340 err = AUDIO_EOF;
341 err.sys = AUDIO_COPY_INPUT_EOF;
342 return (err);
343 }
344 if (cnt > resid)
345 cnt = resid;
346
347 // Fix the alignment to make sure we're not splitting frames
348 err = AUDIO_SUCCESS;
349 if (GetHeader().Bytes_to_Bytes(cnt) > 0) {
350 // Copy as much data as possible
351 memcpy((char *)buf, (char *)((off_t)GetAddress() + offset),
352 (int)cnt);
353 } else {
354 err.sys = AUDIO_COPY_ZERO_LIMIT;
355 }
356
357 // Return the updated transfer size and position
358 len = (size_t)cnt;
359 pos = GetHeader().Bytes_to_Time(offset + cnt);
360
361
362 // Check to see if the endian is right.
363 coerceEndian((unsigned char *)buf, len, localByteOrder());
364
365 return (err);
366 }
367
368 // Copy data to local buffer from specified buffer.
369 // No data format translation takes place.
370 // The object's write position is not updated.
371 AudioError AudioBuffer::
WriteData(void * buf,size_t & len,Double & pos)372 WriteData(
373 void* buf, // source buffer address
374 size_t& len, // buffer length (updated)
375 Double& pos) // start position (updated)
376 {
377 off_t resid;
378 off_t cnt;
379 off_t offset;
380 AudioError err;
381
382 // Copy length, zero return value
383 cnt = (off_t)len;
384 len = 0;
385
386 // Cannot write if buffer or header not valid
387 if (!opened())
388 return (RaiseError(AUDIO_ERR_NOEFFECT));
389
390 // Position must be valid
391 if ((pos < 0.) || (cnt < 0))
392 return (RaiseError(AUDIO_ERR_BADARG));
393
394 // If the starting offset beyond end of buffer, return short write flag
395 if (pos >= GetSize()) {
396 err = AUDIO_EOF;
397 err.sys = AUDIO_COPY_OUTPUT_EOF;
398 return (err);
399 }
400
401 // Limit transfer to remaining room in buffer
402 offset = GetHeader().Time_to_Bytes(pos);
403 resid = (off_t)bufsize - offset;
404 if (resid <= 0) {
405 err = AUDIO_EOF;
406 err.sys = AUDIO_COPY_OUTPUT_EOF;
407 return (err);
408 }
409 if (cnt > resid)
410 cnt = resid;
411
412 // Fix the alignment to make sure we're not splitting frames
413 err = AUDIO_SUCCESS;
414 if (GetHeader().Bytes_to_Bytes(cnt) > 0) {
415 // Copy as much data as possible
416 memcpy((char *)((off_t)GetAddress() + offset), (char *)buf,
417 (int)cnt);
418 } else {
419 err.sys = AUDIO_COPY_ZERO_LIMIT;
420 }
421
422 // Return the updated transfer size and position
423 len = (size_t)cnt;
424 pos = GetHeader().Bytes_to_Time(offset + cnt);
425
426 // The end of a write to a buffer always becomes the buffer EOF
427 setlength(pos);
428 return (err);
429 }
430
431 // AppendData is just like WriteData, except that it guarantees to extend
432 // the buffer if it is not big enough.
433 // The object's write position is not updated.
434 AudioError AudioBuffer::
AppendData(void * buf,size_t & len,Double & pos)435 AppendData(
436 void* buf, // source buffer address
437 size_t& len, // buffer length (updated)
438 Double& pos) // start position (updated)
439 {
440 Double local_length;
441 AudioError err;
442
443 // Cannot write if header not valid
444 if (!hdrset())
445 return (RaiseError(AUDIO_ERR_NOEFFECT));
446
447 // Position must be valid
448 if (pos < 0.)
449 return (RaiseError(AUDIO_ERR_BADARG));
450
451 // If the ending offset is beyond end of buffer, extend it
452 local_length = pos + GetHeader().Bytes_to_Time(len);
453 if (local_length > GetSize()) {
454 if (err = SetSize(local_length))
455 return (err);
456 }
457 return (WriteData(buf, len, pos));
458 }
459
460 // Copy routine to copy direct to destination
461 AudioError AudioBuffer::
AsyncCopy(Audio * to,Double & frompos,Double & topos,Double & limit)462 AsyncCopy(
463 Audio* to, // audio object to copy to
464 Double& frompos,
465 Double& topos,
466 Double& limit)
467 {
468 caddr_t bptr;
469 size_t cnt;
470 size_t svcnt;
471 Double svfrom;
472 Double svto;
473 Double lim;
474 AudioHdr tohdr;
475 AudioError err;
476
477 // Cannot write if buffer or header not valid
478 if (!opened())
479 return (RaiseError(AUDIO_ERR_NOEFFECT));
480
481 tohdr = to->GetHeader();
482 if (limit < 0.)
483 return (RaiseError(AUDIO_ERR_BADARG));
484
485 // Get maximum possible copy length
486 svfrom = GetLength();
487 if (frompos >= svfrom) {
488 limit = 0.;
489 err = AUDIO_EOF;
490 err.sys = AUDIO_COPY_INPUT_EOF;
491 return (err);
492 }
493 lim = svfrom - frompos;
494 if (!Undefined(limit) && (limit < lim))
495 lim = limit;
496
497 limit = 0.;
498
499 bptr = (caddr_t)GetAddress(frompos);
500 if (bptr == 0) {
501 err = AUDIO_EOF;
502 err.sys = AUDIO_COPY_INPUT_EOF;
503 return (err);
504 }
505 cnt = (size_t)GetHeader().Time_to_Bytes(lim);
506 if (cnt == 0) {
507 err = AUDIO_SUCCESS;
508 err.sys = AUDIO_COPY_ZERO_LIMIT;
509 return (err);
510 }
511
512 // Add a bunch of paranoid checks
513 svcnt = (size_t)GetAddress() + (size_t)GetByteCount();
514 if ((bptr + cnt) > (caddr_t)svcnt) {
515 // re-adjust cnt so it reads up to the end of file
516 cnt = (size_t)((caddr_t)svcnt - bptr);
517 }
518 if (GetHeader().Bytes_to_Bytes(cnt) == 0) {
519 err = AUDIO_EOF;
520 err.sys = AUDIO_COPY_INPUT_EOF;
521 return (err);
522 }
523
524 // Write the data to the destination and update pointers/ctrs
525 svfrom = frompos;
526 svto = topos;
527 svcnt = cnt;
528 err = to->WriteData(bptr, cnt, topos);
529 limit = topos - svto;
530 frompos = svfrom + limit;
531
532 // Report short writes
533 if (!err && (cnt < svcnt)) {
534 err.sys = AUDIO_COPY_SHORT_OUTPUT;
535 }
536 return (err);
537 }
538