BTimeSource

Derived from: virtual BMediaNode

Declared in: be/media/TimeSource.h

Library: libmedia.so

Allocation: Constructor only

[method summary]

The BTimeSource class represents a clock to which nodes can be slaved. By slaving all your nodes to a single master time source, they can be kept in sync with each other.

If a node can, either by design or as a side benefit of the underlying hardware, provide reliable timing services, it might make sense for it to be derived from BTimeSource as well as from whatever other classes it might be derived from, such as BBufferProducer or BBufferConsumer. Doing so will allow other nodes to be slaved to your node's conception of time.

Note that although a BTimeSource is implemented as a real object (and is therefore not a purely abstract class), other nodes won't call your BTimeSource's member functions directly--instead, your BTimeSource will provide data that other nodes will then read.

There are invisible system implementations of the BTimeSource protocol that serve as stand-ins for other nodes, so if you call BMediaRoster::SetTimeSource() to make one of your nodes (which is derived from BTimeSource) a time source for some other node, the other node might see a system stand-in object, not the actual BTimeSource-derived object.

This abstraction layer serves a valuable purpose: it enforces the desire to prevent any two nodes from having to know anything about each other beyond the Media Kit protocols defined in this chapter; this sort of low-level interdependency is discouraged, because it decreases interoperability.


Keeping Time

Although it can be confusing at first, keep in mind that a node derived from both BTimeSource and BBufferProducer (or BBufferConsumer)--which is therefore a time source, as well as a producer or consumer of buffers--has to deal with two different time concepts. As a BTimeSource, it needs to understand requests in real time, while as a BBufferProducer or BBufferConsumer, it needs to accept requests in performance time.

Real time refers to the actual passage of time, as reported by system_time() or the BTimeSource::RealTime() function. It's measured in microseconds.

Performance time runs in "time units" which aren't necessarily directly related to real time. Since your code will have to deal with both kinds of time, you need to be sure to convert between the two time systems when it's necessary to do so. Use the BTimeSource::RealTimeFor() function to do this.

For example, to calculate a timeout value, given a desired performance time, and an estimated latency on the connection, you might use the following code:

   bigtime_t timeout = TimeSource()->RealTimeFor(performance_time,
            estimated_latency) - TimeSource()->RealTime();

This code converts the performance_time into the driving time source's units, then subtracts the current real time, which results in the desired timeout value.


Constructor


BTimeSource()

protected:

      BTimeSource() 

The standard BTimeSource constructor. You should never directly instantiate a BTimeSource; instead, you should create a node class derived from BTimeSource (and possibly other BMediaNode-derived classes as well) and use the BMediaRoster to instantiate the node as desired.


Member Functions


BroadcastTimeWarp()

      void BroadcastTimeWarp(bigtime_t atRealTime,
         bigtime_t newPerformanceTime)

Whenever time jumps suddenly (for instance, when a seek operation occurs), call this function to inform all slaved nodes that time has jumped in a discontinuous manner. You should also call this function if the time from which your time source derives its time jumps.

At the real time specified by atRealTime, the performance time will instantaneously jump to newPerformanceTime.


GetStartLatency()

      status_t GetStartLatency(bigtime_t *outLatency)

Returns in outLatency the amount of time, in microseconds, needed for the time source to start up, including the time needed to start up any slaved nodes that are started.

RETURN CODES

B_OK. The latency value was returned successfully.

B_NO_INIT. The time source has not been initialized.


GetTime()

      status_t GetTime(bigtime_t *performanceTime, bigtime_t *realTime,
         float *drift)

Returns the most recently published time information for this time source; this information specifies the performance time and real time of the last published time stamp, as well as the drift value, which can be used to interpolate the true current performance time, given a more accurate real time, as follows:

   bigtime_t performanceTime;
   bigtime_t realTime;
   float drift;
   
   while (GetTime(&performanceTime, &realTime, &drift) != B_OK);
   performanceTime = performanceTime + (RealTime() - realTime) * drift;

Note, however, that the resulting performanceTime is the same value you would have gotten by calling PerformanceTimeFor(), which you should use instead.

RETURN CODES

B_OK. The returned information is accurate.

Other values. The returned information is unreliable.


HandleMessage()

protected:

      virtual status_t HandleMessage(int32 code, const void *message, size_t size)

Given a message received on the control port, this function dispatches the message to the appropriate BTimeSource hook function. If the message doesn't correspond to a hook function, an appropriate error be returned.

If your node derives from BTimeSource, your implementation of HandleMessage() should call all inherited forms of HandleMessage().

<<<insert sample code here>>>

RETURN CODES

B_OK. The message was dispatched.

Other errors. The message couldn't be dispatched, possibly because it doesn't correspond to a hook function.


IsRunning()

      bool IsRunning(void)

Returns true if the BTimeSource is currently progressing through time or false if it's stopped.


Now(), PerformanceTimeFor(), RealTimeFor()

      bigtime_t Now(void)
      bigtime_t PerformanceTimeFor(bigtime_t realTime)
      bigtime_t RealTimeFor(bigtime_t performanceTime, bigtime_t withLatency)

Now() returns an approximation of what the current performance time is.

PerformanceTimeFor() returns an estimate of the performance time represented by the specified real time (as returned by BTimeSource::RealTime()).

RealTimeFor(), given a performance time, returns an approximation of the corresponding real time, adjusted by the given latency.


PublishTime()

protected:

      void PublishTime(bigtime_t performanceTime, bigtime_t realTime, float drift)

While your time source is running, you should repeatedly call this function in order to constantly refresh the mapping between real time and performance time. When your time source is stopped, you should call this function once with values of zero for all three arguments.

The arguments have the following meanings:

The drift value makes it possible to interpolate intermediate values. For instance, if playback of a video source is progressing at normal speed, the drift value would be 1.0, indicating that performance time and real time progress at the same rate.

However, if the movie is playing at half-speed, drift would be 0.5, so that for every one unit of real time that passes, only a half-unit of performance time would pass. This information is used to compute times without having to query the time source each time an update must occur.

The data furnished by this function (which you should try to call about 20 times a second, although variations in frequency are acceptable as long as the drift value doesn't change much) may be the only information the rest of the world sees from your node.


RealTime()

      static bigtime_t RealTime(void)

Returns the current absolute real time reference that all time sources measure themselves against. This is the only call that you should rely upon to obtain this value (don't use the Kernel Kit's system_time() function).

As of this time, RealTime() and system_time() do return the same value; however, you shouldn't rely upon this relationship. When doing media stuff, you should always use RealTime().


RealTimeFor() see Now()


Seek()

protected:

      virtual void Seek(bigtime_t performanceTime, bigtime_t atRealTime)

Implement this function to handle a seek request. When a BTimeSource's performance time is adjusted, it needs to broadcast the change to all nodes slaved to it; call BroadcastTimeWarp() to do this.

Be sure to queue at least one seek request, so seek operations can be requested in advance. The seek request should occur at the real time specified by atRealTime.


SendRunMode()

protected:

      void SendRunMode(run_mode mode)

This function transmits the specified mode to all the nodes slaved to this node, so they know that their time source's run mode has changed. This function is called by SetRunMode(); it may or may not make sense to call it elsewhere, depending on your BTimeSource implementation.


SetRunMode()

protected:

      virtual void SetRunMode(run_mode mode)

This hook function is called when someone requests that your node's run mode be changed. Be sure to call through to either BMediaNode::SetRunMode() or BTimeSource::SetRunMode().

Possible values for mode are:

Constant Description
BMediaNode::B_FREEWHEELING Keep data accurate, even if the performance lags or runs too fast.
BMediaNode::B_DECREASE_PRECISION If the performance starts to lag, try to catch up.
BMediaNode::B_INCREASE_LATENCY If the performance starts to lag, increase playout delay so buffers are delivered less frequently.
BMediaNode::B_DROP_DATA If the performance starts to lag, skip data.


SnoozeUntil()

      virtual void SnoozeUntil(bigtime_t performanceTime, bigtime_t withLatency = 0,
         bool retrySignals = false)

Waits until the specified performanceTime (specified in performance time) arrives in real time. If withLatency is non-zero, SnoozeUntil() waits until withLatency microseconds (in real time) prior to the specified performance time; this lets you have time for setup prior to starting some operation.

Because performanceTime is specified in performance time, and withLatency is specified in real time, you can't just subtract withLatency microseconds from performanceTime and snooze until that time, because performanceTime may be passing at a rate faster than or slower than real time (if, for example, the time source is running at double-speed).

If retrySignals is false (as is the default), SnoozeUntil() returns B_INTERRUPTED if it's interrupted by a signal before performanceTime; if retrySignals is true, the function will go right back to sleep and not return until the time has actually arrived.

RETURN CODES

B_OK. No error; the snooze has completed without incident.

B_MEDIA_TIME_SOURCE_STOPPED. The time source is stopped; snoozing on a stopped time source is a bad thing.


Start()

protected:

      virtual void Start(bigtime_t realTime)

This function is called when someone wants the BTimeSource to begin running; the realTime argument indicates the real time at which the time source should start. Implement the function to queue the request as necessary.

Be sure to queue at least one start request, so that start requests can be filed in advance.

A BTimeSource measures start and stop times in real time, not in performance time, because BTimeSources are the objects used to perform the mapping between real time and performance time.


Stop()

protected:

      virtual void Stop(bigtime_t realTime)

Stop() is called when someone wants the BTimeSource to stop; the realTime argument indicates the real time at which the time source should stop running. Implement the function to queue the request.

Be sure to queue at least one stop request, so stop requests can be filed in advance.

A BTimeSource measures start and stop times in real time, not in performance time, because BTimeSources are the objects used to perform the mapping between real time and performance time.






The Be Book, in lovely HTML, for BeOS Release 4.

Copyright © 1998 Be, Inc. All rights reserved.

Last modified November 3, 1998.