496 lines
32 KiB
HTML
496 lines
32 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Be Newsletters - Volume 4: 1999</title><link rel="stylesheet" href="be_newsletter.css" type="text/css" media="all" /><link rel="shortcut icon" type="image/vnd.microsoft.icon" href="./images/favicon.ico" /><!--[if IE]>
|
||
<link rel="stylesheet" type="text/css" href="be_newsletter_ie.css" />
|
||
<![endif]--><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Be Newsletters" /><link rel="up" href="volume4.html" title="Volume 4: 1999" /><link rel="prev" href="Issue4-16.html" title="Issue 4-16, April 21, 1999" /><link rel="next" href="Issue4-18.html" title="Issue 4-18, May 5, 1999" /></head><body><div id="header"><div id="headerT"><div id="headerTL"><a accesskey="p" href="Issue4-16.html" title="Issue 4-16, April 21, 1999"><img src="./images/navigation/prev.png" alt="Prev" /></a> <a accesskey="u" href="volume4.html" title="Volume 4: 1999"><img src="./images/navigation/up.png" alt="Up" /></a> <a accesskey="n" href="Issue4-18.html" title="Issue 4-18, May 5, 1999"><img src="./images/navigation/next.png" alt="Next" /></a></div><div id="headerTR"><div id="navigpeople"><a href="http://www.haiku-os.org"><img src="./images/People_24.png" alt="haiku-os.org" title="Visit The Haiku Website" /></a></div><div class="navighome" title="Home"><a accesskey="h" href="index.html"><img src="./images/navigation/home.png" alt="Home" /></a></div><div class="navigboxed" id="naviglang" title="English">en</div></div><div id="headerTC">Be Newsletters - Volume 4: 1999</div></div><div id="headerB">Prev: <a href="Issue4-16.html">Issue 4-16, April 21, 1999</a> Up: <a href="volume4.html">Volume 4: 1999</a> Next: <a href="Issue4-18.html">Issue 4-18, May 5, 1999</a></div><hr /></div><div class="article"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Issue4-17"></a>Issue 4-17, April 28, 1999</h2></div></div></div><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Engineering4-17"></a>Be Engineering Insights: Cross Tools for x86 BeOS Development</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Fred</span> <span class="surname">Fish</span></span></div></div></div><p>
|
||
The vast majority of programmers develop applications using native
|
||
toolchains. That is, they use a set of development tools (a "toolchain")
|
||
on a single machine to compile, test, and debug their application running
|
||
on that machine.
|
||
</p><p>
|
||
A common situation, however, is where a programmer, for one reason or the
|
||
other, wants to use one machine (the host machine) to develop
|
||
applications for another machine (the target machine). A cross toolchain
|
||
is one that supports this development model.
|
||
</p><p>
|
||
One of the great features of the GNUPro tools now used in the x86 version
|
||
of BeOS is that they are designed to make it as easy as possible to
|
||
create cross toolchains in a huge variety of weird and wonderful
|
||
combinations. For example, according to the Cygnus website
|
||
<a class="ulink" href="http://www.cygwin.com/">http://www.cygwin.com/</a>, Cygwin currently supports over 125 different
|
||
configurations of native and cross- development GNUPro toolchains.
|
||
</p><p>
|
||
This article presents two cross toolchains for developing x86 BeOS R4
|
||
applications, one hosted on PPC BeOS R4 and the other hosted on RedHat
|
||
Linux 5.2. They can be found at:
|
||
</p><p>
|
||
ftp://ftp.be.com/pub/experimental/tools/gnupro-Hppc-Ti586-bin.tgz<br />
|
||
ftp://ftp.be.com/pub/experimental/tools/gnupro-Hlinux-Ti586-bin.tgz
|
||
</p><p>
|
||
To install the PPC BeOS-hosted toolchain, do something like:
|
||
</p><pre class="screen">
|
||
$ mkdir -p /boot/develop/tools
|
||
$ cd /boot/develop/tools
|
||
$ tar -xvzf gnupro-Hppc-Ti586-bin.tgz
|
||
</pre><p>
|
||
To install the Linux-hosted toolchain, do something like:
|
||
</p><pre class="screen">
|
||
$ su
|
||
Password:
|
||
# cd /usr/local
|
||
# tar -xvzf gnupro-Hlinux-Ti586-bin.tgz
|
||
</pre><p>
|
||
In either case, a directory called "gnupro" will be created and all the
|
||
relevant files will be extracted into a subtree rooted at the gnupro
|
||
directory.
|
||
</p><p>
|
||
In order to provide a concrete example of using the cross toolchain, I
|
||
have taken the BeBounce sample application from the R4 release CD and
|
||
modified it to use a <acronym class="acronym" title="GNUs Not Unix">GNU</acronym>
|
||
<span class="application">autoconf</span> generated <span class="application">configure</span> script and
|
||
associated <code class="filename">Makefile</code> template. This example can be found on the Be ftp
|
||
site at:
|
||
</p><p>
|
||
ftp://ftp.be.com/pub/experimental/tools/gnupro-example.tgz
|
||
</p><p>
|
||
When unpacked, it creates a directory "bounce" and populates it with the
|
||
sample files. To build it using the Linux- hosted cross tools you would
|
||
do something like:
|
||
</p><pre class="screen">
|
||
$ export PATH=/usr/local/gnupro/bin:$PATH
|
||
$ CXX=i586-beos-gcc configure -q
|
||
creating cache ./config.cache
|
||
updating cache ./config.cache
|
||
creating ./config.status
|
||
creating Makefile
|
||
$ make
|
||
i586-beos-g++ -c -g -O2 main.cpp
|
||
i586-beos-g++ -c -g -O2 Crunch.cpp
|
||
i586-beos-g++ -o BeBounce main.o Crunch.o -lbe
|
||
$
|
||
</pre><p>
|
||
(NOTE: for more info while configuring, don't use -q )
|
||
</p><p>
|
||
The currently supplied cross tools include a full set of x86 BeOS R4
|
||
headers and libraries, which allows you to create applications that
|
||
should run on any R4 or later release. If you are a beta tester for a
|
||
later release and want to update these files, here are the steps to
|
||
follow:
|
||
</p><p>
|
||
Create archives of the new include and lib files on an installed version
|
||
of the updated BeOS system and then transfer them to the machine where
|
||
the cross tools are installed:
|
||
</p><pre class="screen">
|
||
$ cd /boot/develop/headers
|
||
$ tar -cvzf /tmp/headers.tgz *
|
||
$ cd /boot/develop/lib/x86
|
||
$ tar -cvzhf /tmp/libs.tgz *
|
||
</pre><p>
|
||
(Note: The 'h' option to tar is very important, to ensure that symbolic
|
||
links are followed. Copy the <code class="filename">headers.tgz</code>
|
||
and <code class="filename">libs.tgz</code> files to the
|
||
machine running the cross tools.)
|
||
</p><p>
|
||
Go to the installed crosstools i586-beos directory, preserve some
|
||
installed files that are part of the toolchain itself, remove the old
|
||
includes and libs, and install the updated versions:
|
||
</p><pre class="screen">
|
||
$ cd /usr/local/gnupro/i586-beos
|
||
$ mv lib/ldscripts ldscripts-save
|
||
$ rm -rf lib include
|
||
$ mkdir lib include
|
||
$ mv ldscripts-save lib/lscripts
|
||
$ cd include
|
||
$ tar -xvzf /tmp/headers.tgz
|
||
$ cd ../lib
|
||
$ tar -xvzf /tmp/libs.tgz
|
||
</pre><p>
|
||
The source for the cross tools can be found in:
|
||
</p><p>
|
||
ftp://ftp.be.com/pub/experimental/tools/gnupro-990420-src.tgz
|
||
</p><p>
|
||
To build the tools from source, you first have to select a root directory
|
||
for the installation. For the PPC host I chose
|
||
<code class="filename">/boot/develop/tools/gnupro</code> and for the Linux host I chose
|
||
<code class="filename">/usr/local/gnupro</code>.
|
||
The following instructions assume you have chosen
|
||
<code class="filename">/usr/local/gnupro</code>, as would be a good choice on most UNIX systems. But
|
||
the actual path is completely arbitrary.
|
||
</p><p>
|
||
Next you have to install the BeOS native include and library files, in
|
||
much the same way as described earlier for updating these files in the
|
||
prepackaged toolchains. In the UNIX case, you would create
|
||
<code class="filename">/usr/local/gnupro/i586-beos</code>
|
||
and then populate an
|
||
<code class="filename">include</code> subdirectory
|
||
with the BeOS headers and a
|
||
<code class="filename">lib</code> subdirectory with the BeOS libraries;
|
||
i.e., the following need to exist and contain the headers and libraries
|
||
respectively:
|
||
</p><p>
|
||
<code class="filename">/usr/local/gnupro/i586-beos/include</code><br />
|
||
<code class="filename">/usr/local/gnupro/i586-beos/lib</code>
|
||
</p><p>
|
||
One last step before actually building the tools is to create the
|
||
toolchain's private install directory tree, which would be (again for the
|
||
Linux case):
|
||
</p><p>
|
||
<code class="filename">/usr/local/gnupro/lib/gcc-lib/i586-beos/2.9-beos-980929</code>
|
||
</p><p>
|
||
The previous step is needed for the cross compiler to be able to locate
|
||
the BeOS include files when building some of the runtime components,
|
||
since they need access to the target's include files, and these are found
|
||
relative to this path by tacking
|
||
<code class="filename">../../../../i586-beos/include</code> on to
|
||
the end of it.
|
||
</p><p>
|
||
Now you're ready to actually configure and build the cross tools. Once
|
||
you've extracted the 70 Mb or so of sources, do something like:
|
||
</p><pre class="screen">
|
||
$ cd gnupro
|
||
$ configure --prefix=/usr/local/gnupro --target=i586-beos
|
||
$ make
|
||
$ make install
|
||
</pre><p>
|
||
Of course, each of the last three steps will generate lots of output to
|
||
the terminal, but should succeed with no errors. If there are errors,
|
||
you'll have to resolve those before proceeding to the next step. After
|
||
doing <code class="command">make install</code>, your cross tools should be ready for use.
|
||
</p><p>
|
||
Regenerating the PPC-hosted cross tools is much trickier, since success
|
||
depends upon having some things from the Geek Gadgets distribution
|
||
installed. In particular, you have to use the GG <span class="application">bcc</span> front end for
|
||
mwcc, which makes mwcc behave much more like gcc. If you really feel the
|
||
need to do this, contact me directly for help, since it is not anywhere
|
||
near as straighforward as generating the Linux-hosted tools.
|
||
</p></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="DevWorkshop4-17"></a>Developers' Workshop: Muxamania Part 2: Better Than Haggis (The Guts of
|
||
SelectorNode)</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Owen</span> <span class="surname">Smith</span></span></div></div></div><p>
|
||
In the previous installment, I introduced a node called <code class="classname">SelectorNode</code>.
|
||
This node allows you to select one of several inputs to pass to a single
|
||
output. This week, I'd like to explore the guts of the node in a little
|
||
more detail.
|
||
</p><p>
|
||
The sample code (plus some scrubbing and general clean-up from last
|
||
week's effort) can again be found at
|
||
</p><p>
|
||
ftp://ftp.be.com/pub/samples/media_kit/Selector.zip
|
||
</p><p>
|
||
I'd like to answer two questions about timing that I encountered whilst
|
||
wrangling with the selector node for last week's diatribe. They are
|
||
</p><ul class="itemizedlist"><li><p>
|
||
When should I send a buffer that I've received?
|
||
</p></li><li><p>
|
||
How can I inform my upstream nodes when my latency changes?
|
||
</p></li></ul><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id783629"></a>Introducing... BMediaEventLooper!</h3></div></div></div><p>
|
||
The node looks vastly different from previous nodes I've presented
|
||
because it derives from the super-nifty and newly christened
|
||
<code class="classname">BMediaEventLooper</code> (formerly known as the
|
||
<code class="classname">MotherNode</code>, and featured in
|
||
Stephen's article two weeks ago) to manage the timing of buffers and
|
||
events. Previously, timing was the trickiest part about developing nodes.
|
||
Now, it takes little more than a few method calls, and leaves you with
|
||
almost no steaming entrails. What does <code class="classname">BMediaEventLooper</code> give you?
|
||
</p><ul class="itemizedlist"><li><p>
|
||
You no longer have to write a Big Bad Service Thread to receive and
|
||
process messages on your port. The <code class="classname">BMediaEventLooper</code> creates and
|
||
maintains the service thread and control port for you (thus, very
|
||
similar to a <code class="classname">BLooper</code> in function).
|
||
</p></li><li><p>
|
||
You no longer have to worry about holding on to events until it's
|
||
time to do them (another feature of the Big Bad Service Threads of the
|
||
past). The <code class="classname">BMediaEventLooper</code> maintains
|
||
a <code class="classname">BTimedEventQueue</code>. You simply
|
||
push events onto the queue as you receive them, and the
|
||
<code class="classname">BMediaEventLooper</code> simply pops events off the queue when they become due.
|
||
</p></li><li><p>
|
||
If all your node wants is to know when Start, Stop, or Seek requests
|
||
become due, your node doesn't have to override Start, Stop, or Seek
|
||
anymore. The <code class="classname">BMediaEventLooper</code> automatically intercepts these events
|
||
and pushes them onto the queue for you.
|
||
</p></li><li><p>
|
||
Your node doesn't have to be limited to storing one Start, Stop, or
|
||
Seek at a time. The <code class="classname">BTimedEventQueue</code> allows you to stack up as many
|
||
events as your heart desires. (Can you say "automation?" I knew you
|
||
could.)
|
||
</p></li><li><p>
|
||
You can and should use <code class="methodname">BMediaEventLooper::EventLatency()</code> to store the
|
||
total latency of your node (that is, processing plus downstream
|
||
latency). <code class="classname">BMediaEventLooper</code> takes this latency into account when it
|
||
determines when to pop events off of the queue.
|
||
</p></li></ul><p>
|
||
You'll see the <code class="classname">BMediaEventLooper</code> in action when I show you how
|
||
<code class="classname">SelectorNode</code> handles buffers.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id783752"></a>Handling the Buffer Binge</h3></div></div></div><p>
|
||
Thanks to <code class="classname">BMediaEventLooper</code>, most of the trickiness in getting buffers
|
||
handled at the proper time is done for you. All <code class="classname">SelectorNode</code> has to do is
|
||
filter the incoming buffers so that only the selected input's buffers get
|
||
through. What we have to determine is: when should <code class="classname">SelectorNode</code> filter
|
||
and send the buffers that it receives?
|
||
</p><p>
|
||
The easiest approach would be to filter buffers as soon as they are
|
||
received, and send them on their merry way as soon as possible, as the
|
||
following diagram illustrates:
|
||
</p><pre class="screen">
|
||
Buffer Received and Handled Buffer Is Late
|
||
| |
|
||
V V
|
||
|OOOOOO|---------------------------------------------------|
|
||
|
||
|
||
Legend:
|
||
|OO| = time spent by processing the buffer
|
||
---- = time spent by waiting
|
||
</pre><p>
|
||
For such a simple filter as Selector, this would be a passable approach.
|
||
However, a more robust node will take pains not to deal with the buffer
|
||
too early. Why? Consider the pathological case where we receive a Stop,
|
||
or are told to change the selected input, between the time we receive the
|
||
buffer (if it was sent super-early) and the time by which the buffer has
|
||
to be sent. If we have already sent the early buffer, then that buffer
|
||
will escape whatever commands we might otherwise want to apply that will
|
||
affect the buffer.
|
||
</p><p>
|
||
Another way to manage buffers would be to handle and send them as late as
|
||
possible so that they'll still arrive on time, taking only the amount of
|
||
time you need to process the buffer into account:
|
||
</p><pre class="screen">
|
||
Buffer Received Buffer Is Late
|
||
| Buffer Handled |
|
||
| | |
|
||
V V V
|
||
|---------------------------------------------------|OOOOOO|
|
||
</pre><p>
|
||
This will take care of the race condition between commands and early
|
||
buffers. However, because you've eliminated all of the slack time you
|
||
might otherwise be able to use to process buffers, your node becomes
|
||
susceptible to jitter from factors such as CPU load and disk activity,
|
||
and your buffers stand a dangerous chance of arriving late.
|
||
</p><p>
|
||
The best approach in this case is to strike a compromise. Let's take raw
|
||
audio and video into account, so that we can calculate how long our
|
||
buffers will be. In this case, we should try to handle the buffer as soon
|
||
as possible, *but not earlier than* the duration of one buffer before the
|
||
time at which the buffer must be sent:
|
||
</p><pre class="screen">
|
||
Buffer Received Buffer Handled Buffer Is Late
|
||
| | |
|
||
V V V
|
||
|-----------------------------|OOOOOO|---------------------|
|
||
<---------------------------->
|
||
Buffer Duration
|
||
</pre><p>
|
||
This will ensure that we properly handle commands that apply to our
|
||
buffer, but it will give us enough room to handle unpredictable delays in
|
||
processing.
|
||
</p><p>
|
||
Fortunately, with the <code class="classname">BMediaEventLooper</code>'s event queue, doing this the
|
||
right way is a snap. There are three simple steps:
|
||
</p><ul class="itemizedlist"><li><p>
|
||
We report our processing latency as being the duration of one buffer,
|
||
plus whatever our estimated scheduling jitter is for our thread.
|
||
</p></li><li><p>
|
||
We calculate our total latency by adding this processing latency to
|
||
the latency downstream.
|
||
</p></li><li><p>
|
||
Finally, we tell the <code class="classname">BMediaEventLooper</code> what our total latency is by
|
||
calling <code class="methodname">SetEventLatency()</code>, so that it pops events at the proper time.
|
||
</p></li></ul><p>
|
||
Here's what it looks like in code:
|
||
</p><pre class="programlisting cpp">
|
||
<span class="type">void</span>
|
||
<code class="classname">SelectorNode</code>::<code class="methodname">Connect</code>(..., <span class="type">media_format&</span> <code class="parameter">with</code>, ...)
|
||
{
|
||
...
|
||
|
||
<span class="comment">// Calculate the processing latency.</span>
|
||
<span class="type">bigtime_t</span> <code class="varname">proc</code> = <code class="function">buffer_duration</code>(<code class="varname">with</code>);
|
||
<code class="varname">proc</code> += <code class="function">estimate_max_scheduling_latency</code>();
|
||
|
||
<span class="comment">// Calculate the downstream latency.</span>
|
||
<span class="type">bigtime_t</span> <code class="varname">downstream</code>;
|
||
<span class="type">media_node_id</span> <code class="varname">ts</code>;
|
||
<code class="methodname">FindLatencyFor</code>(<code class="varname">m output.destination</code>, &<code class="varname">downstream</code>, &<code class="varname">ts</code>);
|
||
|
||
<span class="type">bigtime_t</span> <code class="varname">totalLatency</code> = <code class="varname">proc</code> + <code class="varname">downstream</code>;
|
||
|
||
<span class="comment">// Tell the event queue what our new latency is.</span>
|
||
<code class="methodname">SetEventLatency</code>(<code class="varname">totalLatency</code>);
|
||
...
|
||
}
|
||
</pre><p>
|
||
Now, all we need to do is push buffers onto the queue as we receive them.
|
||
At the proper time, they'll be popped from the queue and handed to
|
||
<code class="methodname">HandleEvent()</code>, which we override to actually send the buffer.
|
||
</p><pre class="programlisting cpp">
|
||
<span class="type">void</span>
|
||
<code class="classname">SelectorNode</code>::<code class="methodname">BufferReceived</code>(<code class="classname">BBuffer</code>* <code class="varname">b</code>)
|
||
{
|
||
<span class="comment">// The B RECYCLE constant means that any buffers</span>
|
||
<span class="comment">// inadvertently left in the queue will be recycled</span>
|
||
<span class="comment">// when the queue is deleted.</span>
|
||
<code class="methodname">EventQueue()</code>-><code class="methodname">PushEvent</code>(<code class="parameter">b</code>-><code class="methodname">Header()</code>-><code class="varname">start_time</code>,
|
||
<code class="classname">BTimedEventQueue</code>::<code class="constant">B_HANDLE_BUFFER</code>, <code class="parameter">b</code>,
|
||
<code class="classname">BTimedEventQueue</code>::<code class="constant">B_RECYCLE</code>, 0);
|
||
}
|
||
|
||
<span class="type">void</span>
|
||
<code class="classname">SelectorNode</code>::<code class="methodname">HandleEvent</code>(<span class="type">bigtime_t</span> <code class="parameter">performance_time</code>,
|
||
<span class="type">int32</span> <code class="parameter">what</code>, <span class="type">const void *</span><code class="parameter">pointer</code>, <span class="type">uint32</span> <code class="parameter">cleanup</code>,
|
||
<span class="type">int64</span> <code class="parameter">data</code>)
|
||
{
|
||
switch (<code class="parameter">what</code>) {
|
||
case <code class="classname">BTimedEventQueue</code>::<code class="constant">B_HANDLE_BUFFER</code>:
|
||
{
|
||
<span class="comment">// It's time to handle this buffer.</span>
|
||
<span class="type"><code class="classname">BBuffer</code>*</span> <code class="varname">b</code> = (<span class="type"><code class="classname">BBuffer</code>*</span>) <code class="parameter">pointer</code>;
|
||
|
||
if (<code class="varname">b</code>-><code class="methodname">Header</code>()-><code class="varname">destination</code>
|
||
!= (<span class="type">uint32</span>) <code class="varname">m_selectedInput</code>)
|
||
{
|
||
<span class="comment">// This buffer doesn't belong to the</span>
|
||
<span class="comment">// selected input, so get rid of it!</span>
|
||
<code class="varname">b</code>-><code class="methodname">Recycle</code>();
|
||
break;
|
||
}
|
||
|
||
<span class="comment">// This buffer does belong to our selected</span>
|
||
<span class="comment">// input, so try to send it.</span>
|
||
if ((! <code class="methodname">IsConnected</code>()) || <code class="methodname">IsStopped</code>()
|
||
|| (! <code class="varname">m_enabled</code>) // output enabled
|
||
|| <code class="methodname">SendBuffer</code>(<code class="varname">b</code>, <code class="varname">m_output</code>.<code class="varname">destination</code>)
|
||
!= <code class="constant">B_OK</code>)
|
||
{
|
||
<span class="comment">// Either we shouldn't send the buffer</span>
|
||
<span class="comment">// or the send failed. In either case,</span>
|
||
<span class="comment">// get rid of the buffer.</span>
|
||
<code class="varname">b</code>-><code class="methodname">Recycle</code>();
|
||
}
|
||
}
|
||
break;
|
||
...
|
||
}
|
||
}
|
||
</pre><p>
|
||
This is a decent approach for the slackers out there like myself.
|
||
However, the astute observer will note one disadvantage to this approach:
|
||
your node's latency is increased to one whole buffer's duration. Stack a
|
||
few of these nodes together in a chain, and you end up with far more
|
||
latency than you really need. So, for you bean counters out there, what
|
||
you really want is to report your standard processing latency when
|
||
handling events as usual, *but* instruct the <code class="classname">BMediaEventLooper</code> to pop
|
||
buffers a buffer's duration early if it can. We're working on building
|
||
this sophistication into <code class="classname">BMediaEventLooper</code> right now, to show up in a
|
||
future release. Stay tuned, O true believers...
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id784325"></a>Captain Hook: Managing the Format and Connections</h3></div></div></div><p>
|
||
Another interesting part of the <code class="classname">SelectorNode</code> deals with negotiating the
|
||
format and the connections.
|
||
</p><p>
|
||
As you can see from the above, the selector node passes buffers blindly,
|
||
so it must enforce that the output connection have the same format as the
|
||
input connections. It does this by rejecting all output connections until
|
||
its first input is connected, and then uses the first input's connection
|
||
format as the non-negotiable format for all future inputs and outputs.
|
||
</p><p>
|
||
Because I'm connecting upstream nodes before downstream nodes in this
|
||
case, there's an additional complication that gets introduced. When I
|
||
begin, the node chain for my application looks something like this,
|
||
including the approximate processing latency for the downstream nodes:
|
||
</p><pre class="screen">
|
||
File Reader Selector Node Output
|
||
latency=1ms latency=50ms
|
||
</pre><p>
|
||
The first connection is made between the file reader and the selector
|
||
node. Once this is done, the file reader will see a downstream latency of
|
||
1ms, because only the selector node is currently downstream.
|
||
</p><pre class="screen">
|
||
File Reader ----------> Selector Node Output
|
||
latency=1ms latency=50ms
|
||
<------------------------>
|
||
downstream latency=1ms
|
||
</pre><p>
|
||
The next connection is made between the file reader and the selector node:
|
||
</p><pre class="screen">
|
||
File Reader ----------> Selector Node --------------> Output
|
||
latency=1ms latency=50ms
|
||
<----------------------------------------------->
|
||
downstream latency=51ms
|
||
</pre><p>
|
||
Because the Output is now connected, the downstream latency for the File
|
||
Reader has just increased tremendously. But there is currently no good
|
||
mechanism for the selector node to tell the File Reader that its latency
|
||
has just changed, so the File Reader still thinks its latency is only
|
||
1ms. The result? All the file reader's buffers end up arriving 50ms late!
|
||
</p><p>
|
||
We've solved this problem by adding two simple functions to the Media Kit
|
||
API for genki/5; you can see these functions in action in SelectorNode:
|
||
</p><ul class="itemizedlist"><li><p>
|
||
<code class="methodname">BBufferConsumer::SendLatencyChange()</code> informs an upstream producer
|
||
what the new downstream latency from us is.
|
||
</p></li><li><p>
|
||
<code class="methodname">BBufferProducer::LatencyChanged()</code> is the corresponding function
|
||
that's called on the upstream producer. The producer then makes
|
||
whatever adjustments are necessary to abide by the new latency.
|
||
</p></li></ul></div><p>
|
||
That's it for this week's installment. Hopefully, this week I've managed
|
||
to give you a taste of stuff we're adding to the Media Kit to make the
|
||
node writer's life easier. As always, let us know what else we can do to
|
||
pave the road for you. And have fun developing those tractor nodes!
|
||
</p></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Gassee4-17"></a>Pricing Power</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Jean-Louis</span> <span class="surname">Gassée</span></span></div></div></div><p>
|
||
As I learn more idioms in my adopted tongue, I'm continuously delighted
|
||
by the expressive power, the conciseness of the American lingo. There are
|
||
some atrocities, of course, such as incentivize, or unavoidable
|
||
infelicities, such as reintermediate, but the term "Pricing Power" struck
|
||
a different chord—the Internet.
|
||
</p><p>
|
||
On the radio, I heard one sage explain our current low inflation as the
|
||
result of the Internet reducing companies' Pricing Power. I thought that
|
||
was as good an explanation as any for what has come to be known as the
|
||
Internet mania. Looking a little more closely, I felt the phrase
|
||
encapsulated even more than the NPR oracle explicitly stated—but
|
||
that's how oracles are—they leave some of the hermeneutics to the
|
||
reader.
|
||
</p><p>
|
||
The seer could have said that the Internet makes comparison shopping
|
||
easier, faster, ubiquitous, universal. As a result, we have a buyer's
|
||
market, prices stay low and, voilà , low inflation. But there is a little
|
||
-- or even a lot—more. You can have low prices and low sales, but what
|
||
the frictionless movement of data also allows is faster, easier,
|
||
ubiquitous, permanent transactions. So, we have lower prices and twice
|
||
higher volumes, first because of more attractive tags, and second because
|
||
of easier purchases.
|
||
</p><p>
|
||
It looks as though this so called "Internet mania" benefits brick and
|
||
mortar companies by lowering inflation and stimulating business. In other
|
||
words, e-stocks take credit for the rise in "old" stocks. To the point
|
||
where a banker friend of mine, a bricks and mortar banker, worries that
|
||
the most dangerous situation in the stock market today isn't the
|
||
stratospheric level of e-stocks, which still represent a smallish share
|
||
of the stock market's total capitalization. Rather, it is the
|
||
less-heralded inflation in the
|
||
<acronym class="acronym" title="Price/Earnings">P/E</acronym> of conventional companies. They used
|
||
to trade at 10, now they're closer to 30, and he wondered if the benefits
|
||
of less friction in the economy could entirely justify such a rise. In
|
||
his view, the height of the fall might not look forbidding but,
|
||
considering the mass of the falling object, one might rethink one's
|
||
evaluation of potential damages.
|
||
</p><p>
|
||
But, there is perhaps more to the oracle, more than a buyer's market and
|
||
its consequences. As any good oracle, it might also pose the opposite
|
||
interpretation. How about the Internet creating a seller's market? Look
|
||
at eBay, and its recently announced acquisition of a respected
|
||
conventional auction house, Butterfield and Butterfield of San Francisco.
|
||
</p><p>
|
||
Just as the efficient circulation of information contributes to lower
|
||
prices, it seems that eBay, by efficiently matching sellers and buyers,
|
||
liberates bottled-up supply and demand, creating an apparently illogical
|
||
combination of higher prices for the contents of my attic and better
|
||
prices for people looking for that stuff. Thus the conclusion that a
|
||
conventional auction house would be synergistic with its cyber-sibling.
|
||
Butterfield's experience and reputation make higher price items easier
|
||
appraise and sell, and eBay is a great broadcast vehicle for the
|
||
information, and a great net to catch goods and sellers with. Another
|
||
great retroactively obvious Internet story. Where are the next ones?
|
||
</p></div></div><div id="footer"><hr /><div id="footerT">Prev: <a href="Issue4-16.html">Issue 4-16, April 21, 1999</a> Up: <a href="volume4.html">Volume 4: 1999</a> Next: <a href="Issue4-18.html">Issue 4-18, May 5, 1999</a> </div><div id="footerB"><div id="footerBL"><a href="Issue4-16.html" title="Issue 4-16, April 21, 1999"><img src="./images/navigation/prev.png" alt="Prev" /></a> <a href="volume4.html" title="Volume 4: 1999"><img src="./images/navigation/up.png" alt="Up" /></a> <a href="Issue4-18.html" title="Issue 4-18, May 5, 1999"><img src="./images/navigation/next.png" alt="Next" /></a></div><div id="footerBR"><div><a href="http://www.haiku-os.org"><img src="./images/People_24.png" alt="haiku-os.org" title="Visit The Haiku Website" /></a></div><div class="navighome" title="Home"><a accesskey="h" href="index.html"><img src="./images/navigation/home.png" alt="Home" /></a></div></div><div id="footerBC"><a href="http://www.access-company.com/home.html" title="ACCESS Co."><img alt="Access Company" src="./images/access_logo.png" /></a></div></div></div><div id="licenseFooter"><div id="licenseFooterBL"><a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/" title="Creative Commons License"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by-nc-nd/3.0/88x31.png" /></a></div><div id="licenseFooterBR"><a href="./LegalNotice.html">Legal Notice</a></div><div id="licenseFooterBC"><span id="licenseText">This work is licensed under a
|
||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/">Creative
|
||
Commons Attribution-Non commercial-No Derivative Works 3.0 License</a>.</span></div></div></body></html>
|