java™ stream assembly api programmer’s...

Click here to load reader

Post on 04-Aug-2021

3 views

Category:

Documents

0 download

Embed Size (px)

TRANSCRIPT

book.bookSun Microsystems, Inc. 901 San Antonio Road Palo Alto, CA 94303 U.S.A. 650-960-1300
Java™ Stream Assembly API Programmer’s Guide
Java Stream Assembly API, Version 1.0, Community Draft
Java 2 Platform, Standard Edition, Version 1.4
December 2004
Please Recycle
Copyright © 2004 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, CA 95054, U.S.A. All rights reserved.
Sun Microsystems, Inc. has intellectual property rights relating to technology embodied in the product that is described in this document. In particular, and without limitation, these intellectual property rights may include one or more of the U.S. patents listed at http:// www.sun.com/patents and one or more additional patents or pending patent applications in the U.S. and in other countries.
This document and the product to which it pertains are distributed under licenses restricting their use, copying, distribution, and decompilation. No part of the product or of this document may be reproduced in any form by any means without prior written authorization of Sun and its licensors, if any.
Third-party software, including font technology, is copyrighted and licensed from Sun suppliers.
Sun, Sun Microsystems, the Sun logo, Java, and J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
The Adobe® logo is a registered trademark of Adobe Systems, Incorporated.
Federal Acquisitions: Commercial Software - Government Users Subject to Standard License Terms and Conditions.
DOCUMENTATION IS PROVIDED “AS IS” AND ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD TO BE LEGALLY INVALID.
Copyright © 2004 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, CA 95054, Etats-Unis. Tous droits réservés.
Sun Microsystems, Inc. a les droits de propriété intellectuels relatants à la technologie incorporée dans le produit qui est décrit dans ce document. En particulier, et sans la limitation, ces droits de propriété intellectuels peuvent inclure un ou plus des brevets américains énumérés à http://www.sun.com/patents et un ou les brevets plus supplémentaires ou les applications de brevet en attente dans les Etats - Unis et dans les autres pays.
Ce produit ou document est protégé par un copyright et distribué avec des licences qui en restreignent l’utilisation, la copie, la distribution, et la décompilation. Aucune partie de ce produit ou document ne peut être reproduite sous aucune forme, parquelque moyen que ce soit, sans l’autorisation préalable et écrite de Sun et de ses bailleurs de licence, s’il y ena.
Le logiciel détenu par des tiers, et qui comprend la technologie relative aux polices de caractères, est protégé par un copyright et licencié par des fournisseurs de Sun.
Sun, Sun Microsystems, le logo Sun, Java, J2SE, et docs.sun.com, sont des marques de fabrique ou des marques déposées de Sun Microsystems, Inc. aux Etats-Unis et dans d’autres pays.
Le logo Adobe® est une marque déposée de Adobe Systems, Incorporated.
LA DOCUMENTATION EST FOURNIE "EN L’ÉTAT" ET TOUTES AUTRES CONDITIONS, DECLARATIONS ET GARANTIES EXPRESSES OU TACITES SONT FORMELLEMENT EXCLUES, DANS LA MESURE AUTORISEE PAR LA LOI APPLICABLE, Y COMPRIS NOTAMMENT TOUTE GARANTIE IMPLICITE RELATIVE A LA QUALITE MARCHANDE, A L’APTITUDE A UNE UTILISATION PARTICULIERE OU A L’ABSENCE DE CONTREFAÇON.
Contents
Media Streams 1
2. Java Stream Assembly API Overview 7
Purpose of the Java Stream Assembly API 7
Design Requirements 8
Usage Scenarios 8
Fundamental Concepts 8
Applications and Components 20
Roles and Responsibilities 21
Why Use a Lookup Service? 28
Establishing a Stream Between Two JsaComponents 29
Controlling the Stream Flow 33
Monitoring Stream Flow Events 35
Delivering Broadcast Video 38
Configuring Streams, iTV Example 66
Stream Processing, iTV Example 68
4. Developing Components 69
iv Java Stream Assembly API Programmer’s Guide • December 2004
Choosing an Implementation Strategy 71
Modeling 74
Working with Native Objects 79
Naming and Lookup 79
Providing Security Policies 79
Java Stream Assembly API Specification 81
Java Stream Assembly Reference Implementation 81
JNDI (Java Naming and Directory Interface) 81
JNI (Java Native Interface) 82
JMX (Java Management Extensions) 82
RMI (Remote Method Invocation) 82
Contents v
vi Java Stream Assembly API Programmer’s Guide • December 2004
Figures
FIGURE 1 Media Delivery Mechanisms 4
FIGURE 2 Relationship of Streams to Source and Sink Ports 9
FIGURE 3 Component Hierarchy 11
FIGURE 4 Stream Source and Stream Sink 12
FIGURE 5 Stream Control State Diagram 13
FIGURE 6 Java Stream Assembly API Tiers 20
FIGURE 7 Block Diagram: Broadcast Video Code Example 39
FIGURE 8 Broadcast Video Initialization Sequence 40
FIGURE 9 Broadcast Video Changes During Operation Sequence 44
FIGURE 10 Broadcast Video Stream Processing Sequence 45
FIGURE 11 Block Diagram: VOD Example 47
FIGURE 12 VOD Initialization Sequence 50
FIGURE 13 Sequence for Creating NetSink and Opening Ports 56
FIGURE 14 Creating Streams and Configuring Router Processing 58
FIGURE 15 Block Diagram: iTV 60
FIGURE 16 Initialization Sequence, iTV Example 61
FIGURE 17 I/O Setup Sequence, iTV Example 63
FIGURE 18 Stream Configuration and Processing, iTV Example 66
FIGURE 19 Shared Library Component Development Model 72
FIGURE 20 Separate Application Component Development Model 74
FIGURE 21 Typical UML Class Diagram 75
vii
viii Java Stream Assembly API Programmer’s Guide • December 2004
Tables
TABLE 2 MPEG-2 Table Controls 10
TABLE 3 Valid Transitions from Each State 14
TABLE 4 Descriptions of the Control Types 16
TABLE 5 Descriptions of Position Types 18
ix
x Java Stream Assembly API Programmer’s Guide • December 2004
Code Samples
CODE EXAMPLE 2 Looking Up a JsaComponent 29
CODE EXAMPLE 3 Looking Up a JsaComponentFactory 29
CODE EXAMPLE 4 Creating a Stream Connection Using the Default Strategy 31
CODE EXAMPLE 5 Creating a Custom Strategy 31
CODE EXAMPLE 6 Creating a Stream Connection Using a Custom Strategy 32
CODE EXAMPLE 7 Controlling the Stream in the Most Basic Manner 33
CODE EXAMPLE 8 Using Position-Based Stream Control 34
CODE EXAMPLE 9 Implementing ControlContext 36
CODE EXAMPLE 10 Providing a BitRateOutOfRangeParams Object 37
CODE EXAMPLE 11 Monitoring an Overflow Event 38
CODE EXAMPLE 12 Creating a Processor Instance 41
CODE EXAMPLE 13 Creating and Assigning Attributes to Outputs and Inputs 41
CODE EXAMPLE 14 Getting and Checking Media Attributes 42
CODE EXAMPLE 15 Creating and Opening a File Source Instance 42
CODE EXAMPLE 16 Connecting Sources and Sinks 43
CODE EXAMPLE 17 Processing Streams, Broadcast Video Example 46
CODE EXAMPLE 18 Changes During Operation, Broadcast Video Example 47
CODE EXAMPLE 19 Initialization, VOD Example 51
CODE EXAMPLE 20 RTSP Describe Interaction, Client/Server Communication 51
CODE EXAMPLE 21 RTSP Describe Interaction, Server Code, VOD Example 52
xi
CODE EXAMPLE 23 Create the RTP and RTCP Streams 53
CODE EXAMPLE 24 Creating a session object, VOD Example 55
CODE EXAMPLE 25 Getting the SDP Track Attributes, VOD Example 55
CODE EXAMPLE 26 Setting Up the Input Control Node, VOD Example 55
CODE EXAMPLE 27 Create and Connect Stream and Control Node, VOD Example 55
CODE EXAMPLE 28 Creating the Net Sink Factory and Instance, VOD Example 57
CODE EXAMPLE 29 Opening the RTP and RTCP Sink Ports, VOD Example 57
CODE EXAMPLE 30 Creating the RTP and RTCP Streams, VOD Example 59
CODE EXAMPLE 31 Configuring Processor Routing, VOD Example 59
CODE EXAMPLE 32 Playing the Video Selection, VOD Example 59
CODE EXAMPLE 33 Initialization, iTV Example 62
CODE EXAMPLE 34 Setting Up Outputs and Inputs, iTV Example 64
CODE EXAMPLE 35 Configuring Streams, iTV Example 67
CODE EXAMPLE 36 Stream Processing, iTV Example 68
xii Java Stream Assembly API Programmer’s Guide • December 2004
Preface
This programmer’s guide explains the video stream assembly environment for which the JavaTM
Stream Assembly API was designed. It also describes how to use the API to perform the typical tasks
that it was designed to do.
Note – This programmer’s guide draft is intended to support the community draft of JSR 158 by providing an example of the documentation that will be made available with the finished API. The code examples in this draft are based on preliminary versions of the API and should be considered descriptive rather than authoritative.
To download the latest version of this document, go to http://www.jcp.org/en/jsr/detail?id=158
How This Book Is Organized Chapter 1 describes the video stream assembly environment and introduces the terms and concepts used in it.
Chapter 2 introduces the Java Stream Assembly API and explains the terms and concepts that relate specifically to it.
Chapter 3 provides sample code and tips for programmers developing applications that use the Java Stream Assembly API.
Chapter 4 provides sample code and tips for programmers developing components that use the Java Stream Assembly API.
Chapter 5 provides sample code and tips for deployers of applications and components that use the Java Stream Assembly API.
xiii
Audience Definition The Java Stream Assembly API platform defines several distinct roles in the application development and deployment life cycle: product provider, application component provider, application assembler, and deployer. These role definitions are intended as an aid in identifying the tasks performed by various parties during the development, deployment, and running of a Java Stream Assembly application.
Roles can be filled by whatever personnel match an organization's actual application development and deployment workflow. Thus, each role may be performed by a different party or a single party may perform several roles. For example, a programmer may perform the roles of application component provider and application assembler.
The Java Stream Assembly API roles are described below.
Product Provider—A product provider implements a Java Stream Assembly product providing features defined in the Java Stream Assembly specification (JSR 158). A Java Stream Assembly product is free to implement interfaces not specified by the Java Stream Assembly specification in an implementation-specific way.
Application Component Provider—Application component providers produce the building blocks of a Java Stream Assembly application. They typically have expertise in developing reusable components as well as sufficient business domain knowledge. Application component providers need not know anything about the operational environment in which their components will be used.
Application Assembler—An application assembler starts with a set of components developed by application component providers and assembles them into a complete Java Stream Assembly application. The assembler’s expertise lies in providing solutions for a specific problem domain—for example, the financial industry. Application assemblers may not be familiar with the source code of the components that they use, but they use declarative descriptors for the components in order to build applications from them. Like application component providers, they need not know anything about the operational environment in which their applications will be used.
Deployer—A deployer, an expert in a specific operational environment, is responsible for deploying Java Stream Assembly components and applications into that environment. A deployer uses tools supplied by the Java Stream Assembly product provider to perform deployment tasks. A deployer installs components and applications into a Java Stream Assembly server and configures components and applications to resolve all the external dependencies declared by the application component provider and application assembler.
xiv Java Stream Assembly API Programmer’s Guide • December 2004
The following table shows where this guide discusses each role.
Typographic Conventions
Related Documentation
Role Where discussed
Java Stream Assembly Product Provider See Chapters 1, 2, and 5.
Application Component Provider See Chapters 1, 2, and 4.
Application Assembler See Chapters 1, 2, and 3.
Deployer See Chapters 1, 2, and 5.
Typeface Meaning Examples
AaBbCc123 The names of commands, files, and directories; on-screen computer output
Edit your .login file. Use ls -a to list all files. % You have mail.
AaBbCc123 What you type, when contrasted with on-screen computer output
% su Password:
AaBbCc123 Book titles, new words or terms, words to be emphasized
Command-line variable; replace with a real name or value
.
Application Title
Preface xv
Accessing Sun Documentation Online The docs.sun.comsm web site enables you to access Sun technical documentation on the Web. You can browse the docs.sun.com archive or search for a specific book title or subject at:
http://docs.sun.com
Sun Welcomes Your Comments We are interested in improving our documentation and welcome your comments and suggestions. You can e-mail your comments to us at:
[email protected]
xvi Java Stream Assembly API Programmer’s Guide • December 2004
Introduction to Assembling Media Streams
This chapter provides an introduction to media stream assembly concepts in the following sections:
Media Streams
Assembling Media Streams
This chapter introduces concepts related to media streams and multiplexing to help you understand the practical problems that the JavaTM Stream Assembly API aims to solve. This understanding will prepare you to use the API effectively.
Media Streams Stream multiplexers and media streams are at the heart of the Java Stream Assembly API.
A media stream is a continuing, time-critical flow of audio, video, and data information.
A multiplex is a single stream that contains multiple, interleaved media streams. Multiplexing is the process of combining several media streams in such a way that the combined signal can later be separated, or de-multiplexed, into its component parts. Multiplexing can be physical when the data packets are physically interleaved (for example, MPEG2 transport streams), or logical when the data packets are logically combined into a single session. Alternatively, the data packets can remain as separate abstract streams (multiple RTP channels in a single RTSP session).
A multiplex that contains a single program is called a single program multiplex.
A multiplex that contains several programs is called a multi-program multiplex.
The Motion Picture Experts Group Systems (MPEG2-Systems) specification defines the concept of an elementary stream and two forms of multiplexed streams—program streams and transport streams. The elementary stream is a single flow of time-critical content such as audio, video, or data. A multiplexed stream (either a program stream or a transport stream) is a collection of elementary streams that often consists of audio,
1
video, and data. A multiplexed stream also contains tables that characterize the stream content (whether audio, video, or data) and define the address of each elementary stream.
A single program transport stream (SPTS) contains the video and audio signals for one television program. A multi-program transport stream (MPTS) combines the digitized data from multiple programs in a single stream of interleaved data packets, each of which contains a fragment of the digitized data from one of the component media streams.
Transport streams can be manipulated in many ways. The following are just a few examples:
SPTSs may be added to or dropped from the multiplex. Information within the individual streams, such as packet IDs (PIDs), may be
remapped. Input streams that do not include PIDs may have PIDs added.
Functions like the ones listed above are performed by media multiplexers. An IP (Internet Protocol) network is a packet-switched network. Hence, multiplexing in an IP network is logical. Each stream is destined for a different combination of IP address and port. The IP protocol multiplexes the packets associated with the different streams onto the physical layer (such as Ethernet).
Other important concepts include the following:
An RTSP session is a complete RTSP transaction—for example, the viewing of a movie. A session typically consists of a client setting up a transport mechanism for the continuous media stream (SETUP), starting the stream with PLAY or RECORD, and closing the stream with TEARDOWN (source RFC 2326).
An RTP channel is the association among a set of participants communicating with RTP. For each participant, the session is defined by a particular pair of destination transport addresses (one network address plus a port pair—one for RTP and the other for RTCP). In a multimedia session, each medium is carried in a separate RTP session with its own RTCP packets. The multiple RTP sessions are distinguished by different port number pairs and/or different multicast addresses.
One method of transporting media streams, which applies to video delivered over IP, is sending streams that are logically multiplexed at the IP layer to multiple clients over the IP network. Typical manipulations in an IP network include:
A new RTSP session is initiated and established between a new client and the server. RTP or UDP streams associated with that RTSP session are streamed (or added to the
logical IP multiplex) by the Video on Demand (VOD server). Control commands similar to VCR controls are received and executed by the server on
the outgoing media streams.
2 Java Stream Assembly Programmer’s Guide • December 2004
The compression formats for media streams can be any of the available open-standards formats. Common compression schemes are MPEG-2 and MPEG-4. Table 1 gives some idea of the typical bandwidth, in bits per second (BPS), required for transport media streams of various types.
In practice, the bandwidth of any media stream is limited by the maximum throughput of the physical link. For example, the maximum throughput of an Asynchronous Serial Interface (ASI) is 270 Mbps, and the maximum throughput of a Gigabit Ethernet link is approximately 1,000 Mbps.
Two challenges must be overcome before servers and intermediate equipment can handle media streams effectively.
The first challenge is to process and transport the huge volumes of data contained in the media streams, where processing means to manipulate the media stream as it moves through a component. A multiplexer is a type of processor that combines media streams. It is a particularly significant type because multiplexing is central to video delivery.
The second challenge—which compounds the first one—is that all the data in a media stream must be processed in real time, since any data that does not arrive on time is essentially worthless.
Typical stream-handling functions include the following:
Combining audio, video, interactive, and other data to create a Single Program Multiplex (SPTS or RTP channels for a single RTSP session).
Inserting new data, such as advertising or metadata, into individual program transport streams.
Combining SPTSs to create a multiple program multiplex (for example, an MPTS). Removing a program from a multiple program multiplex. Inserting a program into a multiple program multiplex (for example, dropping a
service in MPTS or initiating an RTSP session).
Because of the tremendous volume of data being transported, an important design consideration for video servers is the avoidance of unnecessary copies of the same media stream data. That is, when moving data from an input port to an output port, data that exists at one level (for example, the device level) should not be unnecessarily copied to another level (for example, the operating system level). The Java Stream Assembly API
TABLE 1 Comparison of Bandwidth Requirements
Content Typical Range
Audio 28-400 Kbps
HDTV 10-60+ Mbps
Chapter 1 Introduction to Assembling Media Streams 3
addresses the issue of extra data copies by providing multiple methodologies for transporting data. For example, it Java Stream Assembly supports intra-process shared memory to reduce stream copying.
Assembling Media Streams Assembly is the process of combining media streams to create a multiplex. Media multiplexers are hardware or software components that assemble media streams.
Media Delivery Mechanisms
Two transport mechanisms are possible. The Java Stream Assembly API abstracts these transport mechanisms to handle both in a generic way, as shown in FIGURE 1.
FIGURE 1 Media Delivery Mechanisms
In one case, RTP/UDP and IP comprise the protocol and transport layers, respectively. In the other, MPEG-2 functions as both the protocol and transport layers. The Java Stream Assembly API supports both delivery mechanisms.
4 Java Stream Assembly Programmer’s Guide • December 2004
Controlling Multiplexers
The control of multiplexers involves several procedures:
Starting and stopping media streams—This includes starting, stopping, pausing, and resuming the streams, as well as configuring, starting, and resetting the multiplexer.
Modifying the data within media streams—This includes processing the data to add and drop services, adding interactive data, adding special data like Teletext, and mapping services from one input to another.
Monitoring the performance of the multiplexer—Applications that use the Java Stream Assembly API can monitor the performance of the multiplexer. For example, the API provides access to transport stream overflow and underflow events, which are indicators of congestion.
Feeding Data to Multiplexers
Multiplexers typically consume data at high bit rates. It is normal to have data either “pushed” to the multiplexer or “pulled” from the multiplexer at constant or variable rates. The source of the data can be a broadcast stream, IP stream, or local or remote file source.
When real-time data is made available to the multiplexer, it is important to meet deadlines to ensure that the multiplexer is neither overloaded nor starved.
Due to the sheer volume of data that a multiplexer can consume, it is typical to support different modes for moving data in and out of the multiplexer. The Java Stream Assembly API supports the most common mode, including shared memory segments to avoid unnecessary data copies. Further details are available in Section “Ports” on page 10.
Chapter 1 Introduction to Assembling Media Streams 5
6 Java Stream Assembly Programmer’s Guide • December 2004
CHAPTER 2
Java Stream Assembly API Overview
This chapter provides an overview of the JavaTM Steam Assembly API. It includes the following sections:
Purpose of the Java Stream Assembly API
Design Requirements
Usage Scenarios
Fundamental Concepts
Packages
Purpose of the Java Stream Assembly API The Java Stream Assembly API provides a standard interface for controlling the hardware and software components used to assemble and deliver multiplexed media streams that contain broadcast video, on-demand video, interactive media, and other time-critical content. Using this API, software developers can write Java applications to control and monitor any video server or other media stream assembly system or component that supports the Java Stream Assembly API.
The Java Stream environment consists of media stream inputs (sources), stream processors that manipulate the media stream, and outputs (sinks). Sources and sinks may connect directly to an ASI or Gigabit Ethernet interface, or to some higher-level resource such as a network or file system. A common configuration consists of multiple sources, at least one processor, and at least one sink, residing on a single server. Other configurations are possible, however, including distributed architectures.
7
Design Requirements The Java Stream Assembly API was designed to meet the following requirements:
Must provide the ability to discover and configure multiplexers. Must provide control functions for assembling, starting, stopping, adding, and
dropping streams. Must support both MPEG2 transport and IP streams. Must support the monitoring and reporting of stream events, such as stream
underflow/overflow events.
Usage Scenarios Broadcast Video—Sending the same stream to many different subscribers
simultaneously.
On-demand Video—Sending different streams to different subscribers, as requested in real time by subscribers. Also called Video On Demand (VOD).
Interactive Television—Sending subscribers executable programs that are executed in a set-top box and displayed on a television. These programs offer some degree of interactivity, such as switching between pages of information (for example, between a five-day extended weather forecast page and a Doppler weather radar page). Also called iTV.
Fundamental Concepts This section introduces the following important concepts in the context of the Java Stream Assembly API:
Streams
Ports
Processors
Streams
As described in the “Media Streams” section of Chapter 1, a media stream is a continuing, time-critical flow of audio, video, and data. In the context of the Java Stream Assembly API, however, the term stream means a media stream flowing between the output port (source port) of any component and the input port (sink port) of any other component, as shown in FIGURE 2.
FIGURE 2 Relationship of Streams to Source and Sink Ports
An MPEG-2 elementary stream is a stream of packets of a single element, which can be video, audio, or other data. These elementary stream packets are logical blocks of compressed data of varying sizes. The size and type of logical blocks depend on the stream. For instance, while typical elementary stream packets for video are pictures, for audio they are frame units.
These variably-sized blocks of elementary stream data are further packetized into units of constant size in an MPEG-2 transport stream. These constant-size units of 188 bytes are called MPEG-2 transport stream (TS) packets. TS packets of various elementary streams that belong to a single program are multiplexed together in a single-program MPEG-2 transport stream (SPTS). TS packets of each elementary stream carry a unique identifier called a Packet ID (PID). The Program Map Table (PMT) uniquely identifies the elementary streams and their PIDs.
When an MPEG-2 transport stream carries elementary streams belonging to multiple programs, it is called a multi-program transport stream (MPTS). The Program Association Table (PAT) gives the association between programs and the constituent streams. For an SPTS, the PAT identifies only one program.
Chapter 2 Java Stream Assembly API Overview 9
The Java Stream Assembly API supports PATs and PMTs in detail with interfaces to synthesize and analyze them. TABLE 2 describes these interfaces. The Java Stream Assembly APIs must carry other program-specific and service-specific tables as well, but these are not supported in detail.
Ports
A port is a logical node that represents the point at which a stream enters or leaves a Java Stream Assembly component. Because components can be either physical devices or processes, a port does not always correspond to a physical interface.
Ports can be either source ports or sink ports, where “source” and “sink” describe the relationship of the port to the stream, rather than to the component. Thus, the port associated with the component at which a stream originates is the source port for that stream, and the port associated with the component at which the stream terminates is the sink port. A source port is therefore always the output of some component, and a sink port is always the input to some component.
In addition to being classified as sources or sinks according to their relationships to streams, ports are also classified according to the programming model used to move data between them (see “Moving Data Between Components: Port Types” on page 19 for more information). The three data-movement models, or port types, are:
Local Model—Used for moving data between components running on or associated with the same machine using shared memory segments.
Directed Model—Used for moving low bit-rate data between components through the Java layer, this data model allows you to use Java calls to manipulate the data.
Remote Model—Typically used for moving data between components that are networked together but not running on or associated with the same machine, this data model uses TCP/IP or some other networking protocol.
TABLE 2 MPEG-2 Table Controls
Class Table Manipulation Function
javax.mediastream.format.PAT Identifies MPEG-2 programs in a transport stream.
javax.mediastream.format.PIDMappingPair Reads and writes the 'to' and 'from' the Program IDs (PIDs). A set of 'to' and 'from' values is called a 'mapping pair'.
javax.mediastream.format.PMT Provides an abstraction of the Program Map Table defined in MPEG-2 systems. Provides read/write access to individual table fields.
10 Java Stream Assembly Programmer’s Guide • December 2004
The source and sink ports at opposite ends of a stream must use the same data- movement model (see “Matching Port Types” on page 20 for more information).
Components
The Java Stream Assembly API defines three main types of components (shown with bold borders in FIGURE 3):
Components that have one or more input ports and one or more output ports are called processors (StreamProcessor). Processors manipulate media stream elements via the InputMediaProcess interface and route streams from input ports to output ports.
Components that have one or more source ports and no sink ports are called stream sources (StreamSource). Stream sources can be ASI cables, network devices, computer file systems, or storage devices.
Components that have one or more sink ports and no source ports are called stream sinks (StreamSink). Stream sinks, like stream sources, can be ASI cables, network devices, computer file systems, or storage devices.
FIGURE 3 Component Hierarchy
Of course, some stream sink components have physical outputs of their own, just as some stream source components do. However, stream sources and stream sinks are defined as components with either source or sink ports, but not both.
For the purpose of the Java Stream Assembly API, ports are defined as “logical nodes that define the two ends of a stream,” and streams are defined as “media streams traveling between the output port (source port) of any component within the scope of the Java Stream Assembly API and the input port (sink port) of any other component within the scope of the Java Stream Assembly API.” As shown in FIGURE 2 on page 9, the scope of the Java Stream Assembly API includes only the inner terminus of stream source and stream sink components.
As a result of these definitions, stream sources might have input ports, but those input ports, if they exist, are outside the scope of the Java Stream Assembly API. Likewise, stream sinks might have output ports, but those output ports, if they exist, are outside the scope of the Java Stream Assembly API.
Chapter 2 Java Stream Assembly API Overview 11
Stream Sources and Stream Sinks
In the context of the Java Stream Assembly API, the terms source and sink are used in two different contexts:
Stream Source/Stream Sink—Components that have one or more source ports and one or more sink ports are called processors; they process a stream and pass it on, all under the control of the Java Stream Assembly API. In contrast, components that expose to the Java Stream Assembly API only source ports or sink ports are called either stream sources or stream sinks. Therefore, from the point of view of the Java Stream Assembly API:
all of the ports in a stream source must be source ports, and all of the ports in a stream sink must be sink ports.
A file source is a special type of stream source, and a file sink is a special kind of stream sink. File sources and sinks are associated with files rather than media stream transport interfaces such as ASI.
FIGURE 4 shows a stream source and stream sink in relation to a chain of streams. Note that while the stream source and stream sink might have other physical or logical interfaces than the ones shown, those other interfaces are outside the scope of the Java Stream Assembly API.
FIGURE 4 Stream Source and Stream Sink
Processors
As defined by the Java Stream Assembly API, a processor is an intermediate component in a chain of streams managed by the Java Stream Assembly API. A processor has one or more source ports and one or more sink ports. A processor performs some operation on the stream and passes it on, all under the control of the Java Stream Assembly API.
12 Java Stream Assembly Programmer’s Guide • December 2004
The operation performed by a processor can be simply a pass-through, connecting a stream source to a stream sink. More often, however, the operation involves some manipulation of the stream—for example, adding or dropping specific media streams from multiplexes, or remapping certain PIDs to prevent collisions between identically named packets from different sources that are being merged.
Stream Control
The stream control process is modeled as a state machine, as shown in FIGURE 5.
FIGURE 5 Stream Control State Diagram
Chapter 2 Java Stream Assembly API Overview 13
Transitions from state to state are triggered by invoking one of five methods: init(), prime(), start(), stop(), pause(), or resume(). Not all methods are legal from any given state. FIGURE 5 shows all possible transitions with the exception of those associated with the reset() method, which are omitted to avoid clutter. The reset() method can be invoked from any state, and forces an immediate transition to the Initialized state; if the state machine is already in the Initialized state, it remains in that state.
TABLE 3 presents another view of the state machine. Note that if no transition is defined for an invoked method in the state machine’s current state, the InvalidStateException is generated, and the state remains unchanged.
TABLE 3 Valid Transitions from Each State
State Condition Action
reset() Transition to Initialized state
any other InvalidStateException
start() Transition to Started state
init() Remains in Initialized state
reset() Remains in Initialized state
any other InvalidStateException
stop() Transition to Stopped state
prime() Remains in Primed state
reset() Transition to Initialized state
any other InvalidStateException
pause() Transition to Paused state
reset() Transition to Initialized state
any other InvalidStateException
stop() Transition to Stopped state
pause() Remains in Paused state
reset() Transition to Initialized state
any other InvalidStateException
14 Java Stream Assembly Programmer’s Guide • December 2004
There are two kinds of stream control attributes: control type and position type:
Control Type specifies what you want to do to the stream: start it, stop it, pause it, resume it, preload it, or drain it. See the “Control Types” section, below, for details.
Position Type specifies where in the stream you want the control to be executed. See the “Position Types” section, below, for details.
Control Types
Four of the five control types—start(), stop(), pause(), and resume()—are similar to the equivalent controls on a VCR (subject to the limitations of the media type being viewed, as well as to the constraints described below). The fifth control type, prime(), is not analogous to any VCR control.
The realizable precision of the control arguments depends on the type of media stream being controlled. The position specified by the application may actually differ from the position realized by the implementation, for three reasons.
First, since the media samples are discrete, the position value specified by the application might fall between realizable position values. If the stream is video, for example, the argument might be positioned between video frames. The implementation in this case has no choice but to round to an adjacent, realizable value.
Second, compression techniques often result in video samples that are independent of other media samples, while other video samples, such as interpolation frames, require adjacent frames to reconstruct. The media samples that are independent can be thought of as random access points. The implementation of such compression techniques might therefore round the client position value to an adjacent random access sample, because it cannot reconstruct media samples adjacent to the client position value.
Finally, the stream might be live. For a live stream, if the client position value is in the past (less than the current stream position), the implementation rounds the value to the first realizable value after the current position and performs the control operation. If the client position value is in the future (greater than the current stream position), the implementation defers the control operation until the stream advances to that position. If there are otherwise no exceptions, the control operation returns, but the state machine does not transition until the stream advances to the client position value. The implementation then reports the transition through one of the operations on the ControlContext interface.
stop() Remains in Stopped state
reset() Transition to Initialized state
any other InvalidStateException
State Condition Action
Chapter 2 Java Stream Assembly API Overview 15
The realizable Scale values can also differ from the scale that the client includes as an argument. If the stream is live, for example, the realizable Scale value is often 1.0. See the individual control descriptions in TABLE 4 for details.
TABLE 4 Descriptions of the Control Types
Control Type Description
start() This control starts the media stream from the beginning or, if the stream is live, at the first realizable position.
stop() Because a stream’s source can be either live or storage, stop() does not always behave like the equivalent control on a VCR. For a live stream, if the client position value is less than or equal to the current value, the implementation stops the stream. While the source continues to forward the live stream and the stream position advances, the implementation does not need to journal the live stream to storage. This means that if the client later invokes start(position, scale), the same position as the previous stop(position), the implementation might not be able to reconstruct the portion of the stream between the previous stop() position and the current start() position.
In a situation where the position of the start() is less that the current stream position, the implementation rounds the position to the current stream position (or to the first random access point after the current stream position).
pause() If the state machine transitions to and remains in the paused state, the implementation guarantees that it will preserve the session/execution context at the time the client invokes pause(). This control contrasts with stop(), whose implementation does not guarantee retention of the session/execution context at the time that the client invoked the control. The implementation will resume() at the same position, assuming it is realizable as described above. If the implementation suspects it might lose resources, it should checkpoint the resource state such that after re-acquisition, it can return the resource to the previous context.
16 Java Stream Assembly Programmer’s Guide • December 2004
Note – The minimum conformance criteria require that the implementation support the immediate stream control operations, meaning that it must implement the full state machine. However, if it cannot preserve execution context (such as for a live stream), the pause() operation may cause a transition to the Paused state, followed immediately by a transition to the Stopped state.
As an example, imagine a live stream for which the implementation elects to not journal the stream to storage. When the client invokes pause() and the current state of the state machine is started, the operation returns, but the state machine transitions to the Paused state and then immediately transitions to the Stopped state. The second transition signals the client that the implementation cannot necessarily resume() at the position of the previous pause() operation.
resume() This operation restarts the media stream at the position of the previous pause() operation, assuming that the pause() operation was successful. If the pause() operation was not successful and the state machine transitioned to the Stopped state, the resume() operation functions as start().
prime() The syntax for this operation is prime(Position aPosition, Scale aScale). Prime() serves two purposes.
First, the client can explore realizable values through the prime() operation. The implementation does not transport the stream after the pause(), but it does select the realizable Position and Scale. For example, if the stream is live and the implementation elects to not journal the stream to storage, the implementation might conclude that the realizable Scale is 1.0 and that the realizable Position is the current stream position. If the realizable values matter to the client, it invokes getScale() and getPosition()to learn the extent to which the implementation approximates the arguments.
Additionally, prime() is a hint to the implementation to allocate resources such as buffers, and to forward the first media samples to them. These resource optimizations are not normative, and the implementation can elect to defer the initializations until later—for example, because allocation of resources at a given time would disrupt another stream. However, prime() does let the implementation prepare for subsequent start() invocations.
TABLE 4 Descriptions of the Control Types
Control Type Description
Position Types
TABLE 5 Descriptions of Position Types
Position The Position class is a generic base class that is silent on the metric for position values. Because signatures can contain the base class, while the argument is a subclass, the Position type minimizes the class explosion that would result if the signatures contained each subclass.
Immediate This position type executes the stream control operation at the first realizable position.
Clock This position type executes the stream control at the specified time, using the time value found in the stream.
For video streams, the standard practice is to place a program clock reference into the stream, whose value is often discontinuous in practice. To compensate, there is also a standard for normal play time that begins at the start of a stream with a value of zero and advances at the stream transport rate. (The transport rate need not equate to a scale value of one; for example, multiple versions of the stream might be available in storage with scale values greater than or less than one.) While the normal play time of content after its creation should be continuous, subsequent compositions of multiple stream sources can introduce multiple time lines that make this clock discontinuous.
Sample The position type executes a stream control using video frames, audio samples, or other temporal units to identify a stream position. For most media streams, the sample rate is constant, so knowledge of the sample count allows the client to calculate the stream position as a time value.
Packet This position type executes the stream control at the specified packet number.
It is often difficult for the implementation to inspect inside the stream and recover time values or sample values. The alternative is for the implementation to count packets. For some media streams, the packet count approximates the stream time. For example, audio streams are often of a constant sample size and constant sample rate. If an audio passage (brief collection of contiguous samples) is placed into a packet of constant size, then the packet count becomes a surrogate for the stream time.
For other media streams, such as video, the sample size (in this case, the video frame after compression) is variable. Thus, unless the client knows the stream both before and after compression, the packet count is at best a crude measure of stream time.
18 Java Stream Assembly Programmer’s Guide • December 2004
Physical Interfaces
Stream sources and stream sinks can be of different types. For example, an ASI link, a Gigabit Ethernet link, or a file can act as either a stream source or a stream sink. The Java Stream Assembly API abstracts these different types so that the intermediate JsaComponents do not need to know the exact nature of the source and sink components to which they are connected.
Moving Data Between Components: Port Types
The Java Stream Assembly API defines three standard port types for moving data between components—Local, Remote, and Directed—along with one optional, user-defined port type—ComponentInternal:
Local Port Type—In this port type, the data moves directly between two components that are running or associated with the same machine through a shared or private memory segment. A typical arrangement involves a ring buffer that is accessed directly by the two components.
Directed Port Type—In this port type, data moves through the Java layer. This gives a great deal of programmatic control for nonstandard manipulation of the media stream. It is only practical, however, where bit rates are relatively low.
Remote Port Type—In this port type, components that are not co-located communicate over the data network using TCP/IP or some other networking protocol.
ComponentInternal—Using this optional, user-defined port type, vendors can define vendor-specific implementations that may be viewed as aggregated. For example, an ASI card that also has a multiplexer may have a dedicated low-level means of connection that may be either hardware-assisted or inefficient to map into one of the models above. This approach is discouraged as a general-purpose means of connecting components because it does not promote interoperability.
For a more detailed discussion of the above data movement models, see “Establishing a Stream Between Two JsaComponents” on page 29 of Chapter 3.
When to Use Each Port Type
The Local port type can be used only when both components are running on or associated with the same machine, and when an appropriate buffer is available. The Remote port type can be used any time the components are not co-located. The Directed port type is an alternative to the Local one and should be used only after considering several factors, including the following:
Does some factor, such as a nonstandard processing task, preclude using the Local port type?
Can the data be processed fast enough to meet deadlines? Will the processing demands degrade system performance?
Chapter 2 Java Stream Assembly API Overview 19
Matching Port Types
In the context of the Java Stream Assembly API, a stream can only exist between the source port of one component and the sink port of another component. When moving data, use one of the four port types defined in the Java Stream Assembly API—Local, Remote, Directed and ComponentInternal. In addition, the source and sink ports at opposite ends of a stream must use the same port type. See the previous section, “Moving Data Between Components: Port Types,” for more information on the four defined port types.
Applications and Components The Java Stream Assembly API can be modeled as a set of three tiers, as shown in FIGURE 6.
FIGURE 6 Java Stream Assembly API Tiers
Client Tier—Java applications in this tier configure, manage, and monitor the complete Java Stream Assembly API system. Throughout this programmer’s guide, developers working in the client tier are said to be developing applications. The information in Chapter 3 is intended for application developers.
Integration Tier—Java or C applications in this tier connect and manage streams between components, and provide a publish/subscribe event model to support the run-time monitoring of system activity. Throughout this programmer’s guide, developers working in the integration tier are said to be developing components. The information in Chapter 4 is intended for component developers.
Resource Tier—Java or C applications in this tier control core source, sink, and processing hardware elements. Resource elements are controlled through their abstractions in the integration tier. Throughout this programmer’s guide, developers working in the resource tier are said to be developing components. The information in Chapter 4 is intended for component developers.
20 Java Stream Assembly Programmer’s Guide • December 2004
Roles and Responsibilities The Java Stream Assembly API consists of over 100 specified Java interfaces and classes organized within several packages. About 30% of this total are classes. Responsibility for implementing these classes and interfaces is divided among three roles: the platform provider, the component provider and the client developer.
Platform Provider
Most of the Java Stream Assembly classes will be implemented by a platform provider. There are a handful of important classes provided which underpin the Java Stream Assembly architecture. These are the SessionManager, Session, Stream and StreamSet classes. These are of most use to a Client developer, but an understanding of them is essential. There are a several sorts of support classes such as permissions, positions and connection details that are used by components.
SessionManager
This SessionManager class follows a singleton design pattern. This manager is used to create and track Session objects.
Session
The Session object is used to create streams which are then associated with the session and may then be controlled by operations on the session. This class also provides the facility to create and notify SessionEvent listeners.
Stream
The term stream refers to a media flow between the output Port (source port) of any component and the input Port (sink port) of another component. A Stream object is responsible for connecting the components, selecting a control interface, and monitoring control events. The Stream class makes many calls into a component.
StreamSet
A StreamSet is a collection of streams. This allows several streams to be controlled as an aggregate.
Chapter 2 Java Stream Assembly API Overview 21
Component Provider
The component provider will need to provide implementing classes for most of the Java Stream Assembly interfaces. They will be implementing associated interfaces for either an Endpoint or StreamProcessor. Some of the methods they will implement are needed by the platform. Others are called by a client application.
There are several key interfaces: JSAComponent, ControlNode, Port and Control. Most of these interfaces follow a factory method design pattern.
JSAComponentFactory
This interface provides a means of creating instances of JsaComponent(s) from a given vendor based on a set of attributes or properties.
JSAComponent
This is the base interface for all realized components. This provides methods to create associated ControlNodes. There are many types of JSAComponents. They all fall under two subinterfaces: StreamProcessor or Endpoint. These interfaces themselves have subinterfaces, which typically are the component that the component provider is implementing (for example, StreamNetSource or MPEG2Assembler)
StreamProcessor
A StreamProcessor extends the JSAComponent interface. There are methods to add and remove routes (cross-bar connection) between ControlNodes associated with Ports on the component. A specific realization of a StreamProcessor (for example, MPEG2Assembler) will also have specific methods to implement.
Endpoint
An Endpoint also extends the JSAComponent interface. An EndPoint represents a media source or sink in a chain of JSAComponents -- there are StreamSource and StreamSink subinterfaces. Ultimately the Endpoint to be implemented is itself a subinterface of StreamSource or StreamSink.
A few examples of these include:
Files (StreamFileSource, StreamFileSink) ASI ports (StreamASISource, StreamASISink) Network ports (StreamNetSource, StreamNetSink)
Each of these possesses methods unique to the type of Endpoint component.
22 Java Stream Assembly Programmer’s Guide • December 2004
ControlNode
A ControlNode is associated with a Ports on a component. A ControlNode is a central point of command and control for ports. It provides methods for constructing and connecting Ports, obtaining Control interfaces and registering for events using the EventManager interface.
PortFactory
The PortFactory interface has methods to provide a list of supported PortTypes, to create Port instances of a given PortType. It also has some navigation methods to return associated Ports and ControlNodes.
Port
Port is the base interface for all communications between JSAComponents. Ports represent the points at which a Stream enters or leaves a Component. There are methods to open, close, start and stop.
Ports have a PortType attribute which is classified by the programming model used to move data between them. These are well described in “Ports” on page 10 of this chapter and in Chapter 4, “Developing Components, as well as in the API documentation.
The Component provider must choose one or more PortTypes which match the Component they are implementing. The type of Component being provided and the system architecture often dictate these choices.
PortTypes are either Sinks or Sources. PortTypes support the Push or Pull model. The Component provider must implement the underlying communications mechanism
corresponding to the PrimaryType attribute of the Port (ComponentInternal, Directed, Local or Remote). This mechanism is used to communicate with peer Ports on other components.
These other peer Ports may have been implemented by other component providers. Finally one of the two connected ports must provide ConnectionDetails. Often this will be the “master” port (either a PushSource or PullSink).
ConnectionCtrl/ConnectionDetails
A Port extends the ConnectionCtrl interface. This interface is used by the platform in the process of connecting Ports. It provides a methods to obtain ConnectionDetails from the ConnectionDetails provider port and given this object, complete a connection to the peer Port.
Chapter 2 Java Stream Assembly API Overview 23
Control Factory
The selection process for a Control implementation is characterized in this interface.
Control
The Control interface allows the application to direct the advance of a media stream (equivalent to the function of the controls on a VCR player). The Control interface implements a StreamControl state machine (see the API documentation and “Stream Control” on page 13 in this chapter for details).
The base Control interface specifies a positionless control mechanism. There are methods such as start(), stop(), pause(), resume() and prime(). The PositionControl interface specifies where in the stream the you want the control to be executed. The Position class lists the various position types that can be supported.
Client Developer
A few of the Java Stream Assembly interfaces are expected to be provided by the Client developer. The Client developer’s main job may be to assemble components and platform and provide an application.
One application responsibility is to instantiate components and plumb them together. Another application responsibility is to provide monitoring and control.
ControlContext
This interface provides the client-side context through which the Control reports state transitions.
The design pattern accounts for two features of stream control:
Control operations can take considerable time, and thus are best cast as requests with subsequent confirmations,
Spontaneous state transitions can occur, such as when the Control detects the EndOfStream condition.
EventListeners
The application can register with the EventManager interface to receive a host of events generated by various components.
24 Java Stream Assembly Programmer’s Guide • December 2004
Packages Packages include the following:
javax.mediastream.component—Includes the base classes and interfaces for all components, component factories, and control nodes. This package also includes related Permission classes and exceptions.
javax.mediastream.control—Contains base classes for control interface and control callbacks (ControlContext). This package also includes related Permission classes and exceptions.
javax.mediastream.control.factory—Contains only a factory interface for creating control interfaces.
javax.mediastream.control.position—Includes the base interfaces for position-based control and related callbacks (PositionControlContext).
javax.mediastream.endpoint—Contains generic interfaces representing entry and exit points from a complete stream assembly.
javax.mediastream.events—Contains interfaces for registration of event listeners and the event classes themselves.
javax.mediastream.format—Contains MPEG-2 and SDP related format classes and interfaces.
javax.mediastream.port—Contains base classes and interfaces for ports. Includes port factories, connection control, push and pull sources, and sinks.
javax.mediastream.processor—Contains base classes and interfaces for IP and MPEG based processors.
javax.mediastream.stream—Contains stream and session related classes and interfaces. Also includes Permission classes for session management and related exceptions.
javax.mediastream.stream.events—Contains stream events that may be published to each stream in a given session. Currently the only concrete event type is an RTCP event.
Chapter 2 Java Stream Assembly API Overview 25
26 Java Stream Assembly Programmer’s Guide • December 2004
CHAPTER 3
Developing Applications
For the purposes of this programmer’s guide, the term application refers to an application that runs at the service provider’s premises and that consumes services provided by the JavaTM Stream Assembly API and the components that implement the Java Stream Assembly API’s interfaces. The term client refers to the receiver at the customer’s premises.
This chapter contains the following sections:
Common Development Tasks
Delivering Broadcast Video
Delivering On-Demand Video
Delivering Interactive TV
Common Development Tasks The application developer is responsible for certain tasks. See “Roles and Responsibilities” on page 21 for details.
Regardless of the specific application requirements, an application client developer often needs to perform a number of common tasks. These include:
Looking up a JsaComponent in a naming service. Creating a JsaComponent instance given a JsaComponentFactory.
Looking up a JsaComponentFactory. Establishing a stream between two JsaComponents.
Establishing stream connection using the default connection strategy. Establishing a stream connection using a given strategy. Establishing a stream connection using a specific port type.
Using port types directly. Controlling a stream flow. Monitoring stream flow events. Monitoring “bit-rate out of range” events. Monitoring over-run and under-run events.
27
Creating a Session
Sessions are used to keep track of a collection of streams that share a common life cycle. For example, in the case of a stream assembly that is being used to provide video and audio through RTP, a number of streams relate to a single user session. The Session object can then be used to propagate RTCP events to all streams participating in that user session. The Session object also provides a means of shutting down the collection of streams when the user session terminates.
The SessionManager provides a means of obtaining all active sessions, and therefore all active streams. This makes it possible to gain a complete picture of all running streams and components.
CODE EXAMPLE 1 Creating a Session Session session = SessionManager.getInstance().createSession();
// Creating a collection of three related streams in this session Stream stream1 = session.createStream(); Stream stream2 = session.createStream(); Stream stream3 = session.createStream();
Looking Up a JsaComponent
The Java Stream Assembly API relies on the standard Java Naming and Directory Interface (JNDI) API for component lookup and discovery.
JNDI provides a consistent means of accessing a number of naming and directory services, including LDAP, COS Naming, and DNS. Of these, LDAP is the most likely choice for a Java Stream Assembly API environment.
For details on JNDI, refer to http://java.sun.com/products/jndi/.
Why Use a Lookup Service?
Components may be instantiated directly using the new operator only when the fully qualified name of the class is known. Each vendor provides its own implementation with a different name, however, causing potential lookup problems. Thus, although direct instantiation can be used, it does not support the notion of application portability and component interoperability.
Factory classes solve this problem by providing a means of creating an object instance without knowing the fully qualified class name. However, where the factory class is also a vendor-specific implementation, the problem still exists.
Naming services solve the object creation problem by providing a means of obtaining an object instance by name, allowing you to obtain a single instance of a vendor-specific factory. This factory can then be used to create instances of the object without knowing the vendor-specific class name.
28 Java Stream Assembly Programmer’s Guide • December 2004
Looking Up a JsaComponent
When the administrator has configured and registered a component, an application may retrieve the object by name. Such components are known as administered objects, meaning that they are pre-configured and ready to be used by the application.
CODE EXAMPLE 2 Looking Up a JsaComponent // Create initial lookup context. InitialContext ctx = new InitialContext();
// Look up the 'LiveFeed' by name JsaComponent factory = (JsaComponent)ctx.lookup("LiveFeed");
Looking Up a JsaComponentFactory
In some cases, it is more appropriate to obtain an object factory, such as a file source, than it is to look up a JsaComponent (see the “Stream Sources and Stream Sinks” section in Chapter 2 for more information). Multiple file source instances may be created, each streaming different content and distinguishable only by their source file names.
CODE EXAMPLE 3 Looking Up a JsaComponentFactory // Create initial lookup context. InitialContext ctx = new InitialContext();
// Lookup the 'FileStreamFactory' by name. JsaComponentFactory factory =
(JsaComponentFactory)ctx.lookup("FileStreamFactory");
// Create an instance of the file source from factory. JsaComponent fileStreamComp =
factory.createInstance(new Properties());
In other cases, an administered object approach might be better.The component factory scenario differs from an ASI source, in which the number of physical inputs—and therefore component instances tied to those inputs—is fixed.
Establishing a Stream Between Two JsaComponents
“Ports” on page 10 described the differences between port types. This section explains how to code connections between components.
The primary purpose of the Java Stream Assembly API is to configure, control, and monitor media streams. These streams flow between the ports on JsaComponents. The stream connection between two components is represented by the Stream object. Although the real stream does not flow through this object, the Stream object responsible for connecting the components, selecting a control interface, and monitoring control events.
Chapter 3 Developing Applications 29
Only ports that are compatible can be connected successfully. Automated selection mechanisms called strategies are available to manage port connections, but the Java Stream Assembly API allows application developers to take direct control if needed.
A strategy specifies the order in which ports will be selected for connection under different circumstances. When executing a strategy, the platform automatically takes into consideration and handles all port compatibility issues.
The Java Stream Assembly API includes a default strategy that optimizes performance in the most generic case. Application developers can create additional strategies to optimize performance under specific conditions.
The following subsections deal with the different ways in which you can handle stream connections:
Creating a Stream Connection Using the Default Strategy Creating a Stream Connection Using a Custom Strategy
Most developers will use the default strategy. However, in some components or applications, the optimal order of port selection may differ from that used in the default strategy. The following subsection contains instructions for creating a custom strategy if needed:
Creating a Custom Strategy
Creating a Stream Connection Using the Default Strategy
Each component provides a list of the port types that it supports. A vendor might choose to provide an implementation of the Local (shared-memory) port along with the Remote (TCP/IP) port and omit the Directed (Java platform-enabled) port. Another vendor may choose to implement only the Remote (TCP/IP) port.
When presented with two components to connect, the Stream object first creates a list of compatible pairs of ports from those provided by each component. (For a discussion of what constitutes a compatible pair, see the “Matching Port Types” section of Chapter 2, as well as in “Compatible Port Pairs” on page 33 of this chapter.) The list of compatible pairs is then searched in order of preference: ComponentInternal, Local, Remote, and Directed. The first match is returned as the port type to be used. These PortType objects are then passed back to the component as the argument to the port creation method. The two resulting ports are then connected. This is known as the default port connection strategy, or default strategy.
30 Java Stream Assembly Programmer’s Guide • December 2004
The following code example illustrates the default strategy:
CODE EXAMPLE 4 Creating a Stream Connection Using the Default Strategy // Two components JsaComponent source; JsaComponent sink;
// The session Session jsaSession = SessionManager.getInstance().createSession();
// Create a stream Stream jsaStream = jsaSession.createStream();
// Connect using default strategy jsaStream.connect(source.createControlNode().getPortFactory(),
Creating a Custom Strategy
In situations where the default strategy does not suffice or is inappropriate, component providers can define a custom Strategy. A custom Strategy is developed by implementing the javax.mediastream.stream.Strategy interface. It has a single method called "SelectOption". SelectOption takes an array of compatible port type pairs as argument and returns the port pair selection that must be used for establishing the connection. In the sample code below, a custom strategy is created which is similar to the default strategy except that it favors a directed port over a remote port.
CODE EXAMPLE 5 Creating a Custom Strategy public class CustomStrategy implements Strategy {
public PortTypePair selectOption(PortTypePair[] portTypePairs) {
String[] types = new String[3]; types[0] = PortType.LOCAL_RING_BUFFER_PORT; types[1] = PortType.DIRECTED_PORT; types[2] = PortType.REMOTE_TCP_PORT;
for (int i = 0; i < types.length; i++) { for (int j = 0; j < portTypePairs.length; j++) {
PortTypePair pair = portTypePairs[j]; String primaryType = pair.getSourcePortType().getPrimaryType(); if (primaryType.equals(types[i])) { return pair; }
} } return portTypePairs[0];
Chapter 3 Developing Applications 31
Note – If you want to use a specific port type, create a custom strategy like the one shown above, but populated with just one port type.
Creating a Stream Connection Using a Custom Strategy
Port type selection strategy can be user-defined. In this case, the preference order can be set by creating a stream with a list of port types in the required order of preference.
The following code example shows how to creating a stream using the custom strategy created in the preceding example.
CODE EXAMPLE 6 Creating a Stream Connection Using a Custom Strategy // Create a new Stream with given strategy Stream jsaStream = jsaSession.createStream(strat);
// Connect the JsaComponents using jsaStream.connect(source.createControlNode().getPortFactory(),
sink.createControlNode().getPortFactory() );
PortType
The PortType object describes each port in terms of four attributes:
Source or Sink—A source port represents the source of a media stream. Streams flow from source to sink port. A stream connects a source port and a sink port.
Push or Pull—A push source port pushes data from the source at the required rate for the media. It must be matched by a push sink port. A pull sink port pulls data from the source at the required rate for the media. It must be matched by a pull source port.
Connection Details Provider or Connection Details User—The connection between two ports can be established by the source connecting to the sink, or vice versa. For example, in the case of a Remote (TCP/IP) port, the source could act as a TCP/IP server and wait for connection requests from the sink, or the sink could act as the server. In either case, once a connection is established, the stream can be pumped through the socket.
When a PortType is set as a ConnectionDetails provider, it expects another port to connect to it. Therefore, it makes its connection details available to the other port. The ConnectionDetails object is a base class for all specific connection details. From the perspective of the stream or the application, nothing but the base class is ever visible. The platform obtains the ConnectionDetails from the provider and passes them on to the consumer in the connect call. The client port then initiates a connection to the provider port.
Primary Type—Defines a port as being Local, Directed, Remote, or ComponentInternal (see “Ports” on page 10 for details).
32 Java Stream Assembly Programmer’s Guide • December 2004
Compatible Port Pairs
The stream implementation ensures that the ports being connected are compatible types. To do this, it calls a method (isCompatibleWith) on the PortType that checks port compatibility by verifying that all of the following conditions are met:
Both are of the same primary type, for example, Local. One is a source and the other is a sink. Both support a push model or both support a pull model. One port can provide connection details, while the other can use these details to
create a connection.
In addition, if the primary type is Local (Ring Buffer), isCompatibleWith verifies that the implementations reside on the same physical hosts.
Controlling the Stream Flow
The supported Control types are outlined in the “Control Types” section of Chapter 2. From the developer’s perspective, a single Control interface is required to control the stream. The application may also be interested in either spontaneous or controlled state transitions.
The stream implementation provides the user with a single Control interface for the complete stream. The implementation delegates the user’s commands directly to the underlying ControlNodes. Although each ControlNode may support one or more Control types, they must all support the basic positionless Control type. The user may obtain a list of supported types and select the most appropriate one(s) for the stream.
Note – The list of available types returned to the user for the stream is the subset of types supported by both the source and sink.
Basic Stream Control
The following example illustrates the use of the simplest available method of stream control. Because all ControlNodes must support at least this basic method, the type of control selected is set without checking the capabilities of the node.
CODE EXAMPLE 7 Controlling the Stream in the Most Basic Manner // Two components JsaComponent source; JsaComponent sink;
// The session Session jsaSession = SessionManager.getInstance().createSession();
// Create a stream Stream jsaStream = jsaSession.createStream();
Chapter 3 Developing Applications 33
// Connect using default strategy jsaStream.connect(source.createControlNode().getPortFactory(),
// select basic Position Control type Control control = controlFactory.select(new Position());
// create dummy context - not defined here, see next section ControlContext controlContext = new DummyContext();
// set the control context control.init(controlContext);
// now use control... // create default scale of 1/1 Scale scale = new Scale();
// start playing at normal speed. control.start(scale);
// some time later... control.pause();
// some time later... control.resume(scale);
// some time later... control.stop();
Position-based Stream Control
The following example illustrates the use of a position-based stream control.
CODE EXAMPLE 8 Using Position-Based Stream Control // Two components JsaComponent source; JsaComponent sink;
// The session Session jsaSession = SessionManager.getInstance().createSession();
// Create a stream Stream jsaStream = jsaSession.createStream();
// Connect using default strategy jsaStream.connect(source.createControlNode().getPortFactory(),
// obtain ControlFactory ControlFactory controlFactory = stream.getControlFactory();
// get Set of supported positions Set positions = controlFactory.getPositions();
// check if the one I want is here if(!positions.contains(new ClockPosition())) { throw new Exception("No clock position control available"); }
// select basic Position Control type PositionControl control = (PositionControl)controlFactory.select(new ClockPosition());
// create dummy context - not defined here, see previous section ControlContext controlContext = new DummyContext();
// set the control context control.init(controlContext);
// now use control... // create default scale of 1/1 Scale scale = new Scale();
// create ClockPosition for posn in stream ClockPosition posn = new ClockPosition(123L);
// start playing at normal speed. control.start(posn, scale);
// some time later... control.pause();
// some time later... control.resume(scale);
// some time later... control.stop();
Monitoring Stream Flow Events
Because the state of the control might change spontaneously or might occur after a given command, it is useful to have some means of detecting state transitions.
The user creates an implementation of ControlContext and passes it in to the control as part of the initialization sequence.
A simple implementation of ControlContext might look like this:
Chapter 3 Developing Applications 35
CODE EXAMPLE 9 Implementing ControlContext class DummyContext implements ControlContext{
public java.util.Properties getProperties(){ return new Properties(); }
public void cancelled(int state){ System.out.println("Cancelled"); }
public void drained(){ System.out.println("drained"); }
public void finished(){ System.out.println("finished"); }
public void initialized(){ System.out.println("initialized"); }
public void paused(){ System.out.println("paused"); }
public void stopped(){ System.out.println("stopped"); }
public void stopped(java.lang.Throwable aThrowable){ System.out.println("stopped"); } }
Monitoring “Bit-rate Out of Range” Events
The application may subscribe to “bit-rate out of range” events from a ControlNode. The ControlNode can have more than one subscriber, and each subscriber may determine its own unique definition of “out of range.”
As part of the subscription, the application must include a BitRateOutOfRangeParams object that provides the upper and lower limit thresholds.
CODE EXAMPLE 10 Providing a BitRateOutOfRangeParams Object // Two components JsaComponent source; JsaComponent sink;
// The session Session jsaSession = SessionManager.getInstance().createSession();
// Create a stream Stream jsaStream = jsaSession.createStream();
// Connect using default strategy jsaStream.connect(source.createControlNode().getPortFactory(),
// get the EventManager for the source Control Node EventManager sourceEventManager = stream.getSourceControlNode().getEventManager();
// Create range object 4 Mbps to 1 Mbps BitRateOutOfRangeParams params = new BitRateOutOfRangeParams(4000000, 1000000);
// create simple event handler BitRateOutOfRangeListener listener = new
BitRateOutOfRangeListener(){ public void onEvent(BitRateOutOfRangeEvent e){ System.out.println(e); } };
// register listener with range paramaters sourceEventManager.addBitRateOutOfRangeListener(listener, params);
Monitoring Overflow and Underflow Events
The application can subscribe to overflow and underflow events from a Control Node. An overflow occurs when a push source runs out of buffer space while attempting to send data to the sink. An underflow occurs when a pull sink finds that the buffer contains no data while attempting a read.
Chapter 3 Developing Applications 37
The following example illustrates overflow event monitoring. Underflow monitoring is identical, apart from the name change.
CODE EXAMPLE 11 Monitoring an Overflow Event // Two components JsaComponent source; JsaComponent sink;
// The session Session jsaSession = SessionManager.getInstance().createSession();
// Create a stream Stream jsaStream = jsaSession.createStream();
// Connect using default strategy jsaStream.connect(source.createControlNode().getPortFactory(),
// get the EventManager for the source Control Node EventManager sourceEventManager = stream.getSourceControlNode().getEventManager();
// create simple event handler OverflowListener listener = new OverflowListener() { public void onEvent(OverflowEvent e) { System.out.println(e); } };
// register listener sourceEventManager.addOverflowListener(listener);
Delivering Broadcast Video The scenario in this section illustrates one strategy for delivering broadcast video by completing the following tasks:
Combine a national television broadcast feed (Audio Visual ASI inputs, encoded off-site and originating at a terrestrial TV head-end) with a regional television feed (Audio Visual ASI inputs, encoded locally) to create a multiplex.
Provide correct signaling for the media streams in the new multiplex (by remapping PIDs as required to prevent duplication within the multi-program transport stream).
See the “Streams” on page 9 of Chapter 2 for background information on the Java Stream API classes used for modifying MPEG-2 table values.
38 Java Stream Assembly Programmer’s Guide • December 2004
Note – Each of the following subsections describes a task that a client handling broadcast TV transactions typically must accomplish. For the most part, these tasks are specific to broadcast TV transactions. See “Common Development Tasks” on page 27 of this chapter for a discussion of tasks that are common to more than one use case.
FIGURE 7 is a block diagram of the Broadcast Video example.
FIGURE 7 Block Diagram: Broadcast Video Code Example
Initialization
When working with broadcast video, the initialization sequence consists of the following steps:
Creating a Processor Instance Setting Up Output and Inputs Getting and Checking Media Attributes Creating a File Source Instance Connecting Sources and Sinks
The code examples that follow correspond to the steps listed above. FIGURE 8 shows the sequence diagram for the initialization phase.
Chapter 3 Developing Applications 39
FIGURE 8 Broadcast Video Initialization Sequence
40 Java Stream Assembly Programmer’s Guide • December 2004
The first code example shows how to create a processor instance.
CODE EXAMPLE 12 Creating a Processor Instance // Get the processor factory from the initial context. InitialContext rootContext = new InitialContext();
// Create a processor instance from the processor factory. JsaComponentFactory processorFactory =
(JsaComponentFactory)rootContext.lookup("MyProcessorFactory"); Attributes mpeg2AssemblerAttributes = new BasicAttributes(true); mpeg2AssemblerAttributes.put(new
=(MPEG2Assembler)processorFactory.createInstance(mpeg2Assembler Attributes);
The next code example shows how to create an output (ASISink) and input (ASISource). This involves several substeps: Looking up the ASI output Creating an ASISink instance for it Assigning attributes to the ASISink instance Looking up the ASI input (the live feed) Creating an ASISource instance for it Assigning attributes to the ASISource instance
CODE EXAMPLE 13 Creating and Assigning Attributes to Outputs and Inputs // Look up ASI Output "Local ASIDistribution" // Create an ASISink instance from the ASI sink factory. JsaComponentFactory asiSnkFactory =
(JsaComponentFactory)rootContext.lookup("My Vendor ASI Sink Factory");
Attributes asiSnkAttributes = new BasicAttributes(true); asiSnkAttributes.put(new BasicAttribute("Name", "Local
ASIDistribution")); StreamASISink asiSink =
(JsaComponentFactory)rootContext.lookup("My Vendor ASI Source Factory");
Attributes asiSrcAttributes = new BasicAttributes(true); asiSrcAttributes.put(new BasicAttribute("Name", "Live ASI Feed")); StreamASISource asiSource =
(StreamASISource)asiSrcFactory.createInstance(asiSrcAttributes) ;
Chapter 3 Developing Applications 41
The next code example shows how to determine whether the media attributes associated with the input stream (ASISource) are of the right type for the processor that was created earlier.
CODE EXAMPLE 14 Getting and Checking Media Attributes MediaAttributes liveSrcMediaAttributes =
asiSource.getMediaAttributes(); if (!(liveSrcMediaAttributes instanceof MPEG2Attributes)) {
}
The next code example shows how to open a local insertion file source that will provide the second stream input to the stream processor myMPEG2Assembler, which will multiplex them to generate the final broadcast stream sent to the ASISink. This involves several substeps:
Looking up the file source input Creating a file source instance Assigning attributes to the file source Checking that the file source media type matches the processor type
CODE EXAMPLE 15 Creating and Opening a File Source Instance // Look up the file source input "Local ProgrammingFileSource" // Create a file source instance from the file source factory. JsaComponentFactory fileSourceFactory =
(JsaComponentFactory)rootContext.lookup("My Vendor File Source Factory");
Attributes fileAttributes = new BasicAttributes(true); fileAttributes.put(new BasicAttribute("Name", "Local
ProgrammingFileSource")); StreamFileSource fileSource =
fileSource.getMediaAttributes(); if (!(localMediaAttributes instanceof MPEG2Attributes)) {
}
42 Java Stream Assembly Programmer’s Guide • December 2004
The final code example for the initialization sequence shows how to connect the two sources (one file source and one ASI source) to the processor (MPEG2 assembler) and the processor to the sink (ASI sink). Note the use of a session object to create and manage the media streams.
FIGURE 9 shows the sequence of operations that corresponds to code example 16.
CODE EXAMPLE 16 Connecting Sources and Sinks // Create a session object Session session = SessionManager.getInstance().createSession();
// Connect fileSource and MPEG2 assembler Stream fsMuxStream = session.createStream(); ControlNode fsCn = fileSource.createControlNode(); fsMuxStream.connect(fsCn.getPortFactory(), myMpeg2Assember.createControlNode().getPortFactory() );
myMpeg2Assember.createControlNode().getPortFactory());
(asiSink.createControlNode().getPortFactory(), myMpeg2Assember.createControlNode().getPortFactory());
FIGURE 9 Broadcast Video Changes During Operation Sequence
44 Java Stream Assembly Programmer’s Guide • December 2004
Processing Streams
The processing done in this example is typical of a broadcast video application: the processor inserts local content from a file source at the appropriate times into the live feed (an ASI stream) and passes the processed stream to the ASI sink for local broadcast.
FIGURE 10 shows the sequence for processing broadcast video streams.
FIGURE 10 Broadcast Video Stream Processing Sequence
Chapter 3 Developing Applications 45
The code example for the processing sequence shows how to configure the processor (MPEG2 assembler) and verify that the ASI sink has sufficient bandwidth to handle the output of the processor.
CODE EXAMPLE 17 Processing Streams, Broadcast Video Example // Configure Mpeg2Assembler MyMpeg2Assembler.configureAutoPSI(true); MyMpeg2Assembler.configureRemapPIDs(true); MyMpeg2Assembler.configurePCRRestamp(true); MyMpeg2Assembler.configureForceNIT(asiSrcCn); MyMpeg2Assembler.setPSIInterval(100); MyMpeg2Assembler.setTransportStreamID(200);
if( asiSinkIF[i].getDeviceName().equals("ASIout1") ) { if( asiSinkID[i].getTransportBitRate() < outputBitRate ) {
throw new ProcessorException("Sum of Input bit rates more than output bit rate"); }
break; }
Changes