OpenSolaris_b135/cmd/audio/utilities/AudioExtent.cc

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 1993-2001 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <AudioExtent.h>
#include <stdio.h>

// class AudioExtent methods


// class AudioExtent Constructor
AudioExtent::
AudioExtent(
	Audio*		obj,		// audio object to point to
	double		s,		// start time
	double		e):		// end time
	Audio("[extent]"), ref(obj)
{
	ref->Reference();		// reference audio object
	SetStart(s);			// set start/end times
	SetEnd(e);
}

// class AudioExtent Destructor
AudioExtent::
~AudioExtent()
{
	ref->Dereference();		// clear audio object reference
}

// Get referenced object
Audio* AudioExtent::
GetRef() const
{
	return (ref);
}

// Set referenced object
void AudioExtent::
SetRef(
	Audio*		r)		// new audio object
{
	if (ref == r)			// object is not changing
		return;
	ref->Dereference();		// dereference previous object
	if (r != 0) {
		ref = r;
		ref->Reference();	// reference new object
	} else {
		PrintMsg(_MGET_("AudioExtent:...NULL Audio object reference"),
		    Fatal);
	}
}

// Get start time
Double AudioExtent::
GetStart() const
{
	return (start);
}

// Set start time
void AudioExtent::
SetStart(
	Double		s)		// start time, in seconds
{
	if (Undefined(s) || (s < 0.))
		start = 0.;
	else
		start = s;
}

// Get end time
Double AudioExtent::
GetEnd() const
{
	// If determinate endpoint, return it
	if (!Undefined(end))
		return (end);
	// Otherwise, return the endpoint of the underlying object
	return (ref->GetLength());
}

// Set end time
void AudioExtent::
SetEnd(
	Double		e)		// end time, in seconds
{
	Double		len;

	// If known endpoint and object has known size, do not exceed size
	if (!Undefined(e)) {
		len = ref->GetLength();
		if (!Undefined(len) && (e > len))
			e = len;
	}
	end = e;
}

// Get the length of an audio extent
Double AudioExtent::
GetLength() const
{
	Double		x;

	// If extent end is indeterminate, use the end of the target object
	x = GetEnd();
	// If the object length is indeterminate, then the length is
	if (Undefined(x))
		return (x);
	return (x - start);
}

// Construct a name for the list
char *AudioExtent::
GetName() const
{
	// XXX - construct a better name
	return (ref->GetName());
}

// Get the audio header for the current read position
AudioHdr AudioExtent::
GetHeader()
{
	return (ref->GetDHeader(ReadPosition() + start));
}

// Get the audio header for the given position
AudioHdr AudioExtent::
GetHeader(
	Double		pos)		// position
{
	return (ref->GetDHeader(pos + start));
}

// Copy data from extent into specified buffer.
// No data format translation takes place.
// The object's read position is not updated.
//
// Since the extent could refer to a list of extents of differing encodings,
// clients should always use GetHeader() in combination with ReadData()
AudioError AudioExtent::
ReadData(
	void*		buf,		// destination buffer address
	size_t&		len,		// buffer size (updated)
	Double&		pos)		// start position (updated)
{
	size_t		cnt;
	off_t		buflen;
	Double		off;
	Double		newpos;
	AudioError	err;

	// Save buffer size and zero transfer count
	cnt = len;
	len = 0;

	// Position must be valid
	if (Undefined(pos) || (pos < 0.) || ((int)cnt < 0))
		return (RaiseError(AUDIO_ERR_BADARG));

	// If the end is determinate, check start position and length
	off = pos + start;
	newpos = GetEnd();
	if (!Undefined(newpos)) {
		// If starting beyond eof, give up now
		if (off >= newpos) {
			err = AUDIO_EOF;
			err.sys = AUDIO_COPY_INPUT_EOF;
			return (err);
		}

		// If the read would extend beyond end-of-extent, shorten it
		buflen = GetHeader(pos).Time_to_Bytes((Double)(newpos - off));
		if (buflen == 0) {
			err = AUDIO_EOF;
			err.sys = AUDIO_COPY_INPUT_EOF;
			return (err);
		}
		if (buflen < cnt)
			cnt = (size_t)buflen;
	}
	// Zero-length reads are easy
	if (cnt == 0) {
		err = AUDIO_SUCCESS;
		err.sys = AUDIO_COPY_ZERO_LIMIT;
		return (err);
	}

	// Save the offset, read data, and update the returned position
	newpos = off;
	len = cnt;
	err = ref->ReadData(buf, len, newpos);
	pos = (newpos - start);		// XXX - calculate bytes and convert?
	return (err);
}

// Write to AudioExtent is (currently) prohibited
AudioError AudioExtent::
WriteData(
	void*,				// destination buffer address
	size_t&		len,		// buffer size (updated)
	Double&)			// start position (updated)
{
	len = 0;
	return (RaiseError(AUDIO_ERR_NOEFFECT));
}