root/usr/src/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.
 */

#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));
}