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) 1993-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <AudioExtent.h>
30#include <stdio.h>
31
32// class AudioExtent methods
33
34
35// class AudioExtent Constructor
36AudioExtent::
37AudioExtent(
38	Audio*		obj,		// audio object to point to
39	double		s,		// start time
40	double		e):		// end time
41	Audio("[extent]"), ref(obj)
42{
43	ref->Reference();		// reference audio object
44	SetStart(s);			// set start/end times
45	SetEnd(e);
46}
47
48// class AudioExtent Destructor
49AudioExtent::
50~AudioExtent()
51{
52	ref->Dereference();		// clear audio object reference
53}
54
55// Get referenced object
56Audio* AudioExtent::
57GetRef() const
58{
59	return (ref);
60}
61
62// Set referenced object
63void AudioExtent::
64SetRef(
65	Audio*		r)		// new audio object
66{
67	if (ref == r)			// object is not changing
68		return;
69	ref->Dereference();		// dereference previous object
70	if (r != 0) {
71		ref = r;
72		ref->Reference();	// reference new object
73	} else {
74		PrintMsg(_MGET_("AudioExtent:...NULL Audio object reference"),
75		    Fatal);
76	}
77}
78
79// Get start time
80Double AudioExtent::
81GetStart() const
82{
83	return (start);
84}
85
86// Set start time
87void AudioExtent::
88SetStart(
89	Double		s)		// start time, in seconds
90{
91	if (Undefined(s) || (s < 0.))
92		start = 0.;
93	else
94		start = s;
95}
96
97// Get end time
98Double AudioExtent::
99GetEnd() const
100{
101	// If determinate endpoint, return it
102	if (!Undefined(end))
103		return (end);
104	// Otherwise, return the endpoint of the underlying object
105	return (ref->GetLength());
106}
107
108// Set end time
109void AudioExtent::
110SetEnd(
111	Double		e)		// end time, in seconds
112{
113	Double		len;
114
115	// If known endpoint and object has known size, do not exceed size
116	if (!Undefined(e)) {
117		len = ref->GetLength();
118		if (!Undefined(len) && (e > len))
119			e = len;
120	}
121	end = e;
122}
123
124// Get the length of an audio extent
125Double AudioExtent::
126GetLength() const
127{
128	Double		x;
129
130	// If extent end is indeterminate, use the end of the target object
131	x = GetEnd();
132	// If the object length is indeterminate, then the length is
133	if (Undefined(x))
134		return (x);
135	return (x - start);
136}
137
138// Construct a name for the list
139char *AudioExtent::
140GetName() const
141{
142	// XXX - construct a better name
143	return (ref->GetName());
144}
145
146// Get the audio header for the current read position
147AudioHdr AudioExtent::
148GetHeader()
149{
150	return (ref->GetDHeader(ReadPosition() + start));
151}
152
153// Get the audio header for the given position
154AudioHdr AudioExtent::
155GetHeader(
156	Double		pos)		// position
157{
158	return (ref->GetDHeader(pos + start));
159}
160
161// Copy data from extent into specified buffer.
162// No data format translation takes place.
163// The object's read position is not updated.
164//
165// Since the extent could refer to a list of extents of differing encodings,
166// clients should always use GetHeader() in combination with ReadData()
167AudioError AudioExtent::
168ReadData(
169	void*		buf,		// destination buffer address
170	size_t&		len,		// buffer size (updated)
171	Double&		pos)		// start position (updated)
172{
173	size_t		cnt;
174	off_t		buflen;
175	Double		off;
176	Double		newpos;
177	AudioError	err;
178
179	// Save buffer size and zero transfer count
180	cnt = len;
181	len = 0;
182
183	// Position must be valid
184	if (Undefined(pos) || (pos < 0.) || ((int)cnt < 0))
185		return (RaiseError(AUDIO_ERR_BADARG));
186
187	// If the end is determinate, check start position and length
188	off = pos + start;
189	newpos = GetEnd();
190	if (!Undefined(newpos)) {
191		// If starting beyond eof, give up now
192		if (off >= newpos) {
193			err = AUDIO_EOF;
194			err.sys = AUDIO_COPY_INPUT_EOF;
195			return (err);
196		}
197
198		// If the read would extend beyond end-of-extent, shorten it
199		buflen = GetHeader(pos).Time_to_Bytes((Double)(newpos - off));
200		if (buflen == 0) {
201			err = AUDIO_EOF;
202			err.sys = AUDIO_COPY_INPUT_EOF;
203			return (err);
204		}
205		if (buflen < cnt)
206			cnt = (size_t)buflen;
207	}
208	// Zero-length reads are easy
209	if (cnt == 0) {
210		err = AUDIO_SUCCESS;
211		err.sys = AUDIO_COPY_ZERO_LIMIT;
212		return (err);
213	}
214
215	// Save the offset, read data, and update the returned position
216	newpos = off;
217	len = cnt;
218	err = ref->ReadData(buf, len, newpos);
219	pos = (newpos - start);		// XXX - calculate bytes and convert?
220	return (err);
221}
222
223// Write to AudioExtent is (currently) prohibited
224AudioError AudioExtent::
225WriteData(
226	void*,				// destination buffer address
227	size_t&		len,		// buffer size (updated)
228	Double&)			// start position (updated)
229{
230	len = 0;
231	return (RaiseError(AUDIO_ERR_NOEFFECT));
232}
233