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