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