<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.openhome.org/mediawiki/skins/common/feed.css?270"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://wiki.openhome.org/mediawiki/index.php?feed=atom&amp;target=Simonc&amp;title=Special%3AContributions</id>
		<title>OpenHome - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.openhome.org/mediawiki/index.php?feed=atom&amp;target=Simonc&amp;title=Special%3AContributions"/>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Special:Contributions/Simonc"/>
		<updated>2026-04-17T12:42:08Z</updated>
		<subtitle>From OpenHome</subtitle>
		<generator>MediaWiki 1.16.2</generator>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:TransportPlayAsCommands</id>
		<title>Av:Developer:TransportPlayAsCommands</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:TransportPlayAsCommands"/>
				<updated>2024-05-20T10:40:05Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Add track={json}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Transport PlayAs Options =&lt;br /&gt;
The [[Av:Developer:TransportService | Transport]] service’s &amp;lt;tt&amp;gt;PlayAs&amp;lt;/tt&amp;gt; action takes arguments for &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; (source or group of related sources) and a mode-specific &amp;lt;tt&amp;gt;command&amp;lt;/tt&amp;gt;.  Some standard modes and commands are listed below; other manufacturer-specific options are possible.&lt;br /&gt;
&lt;br /&gt;
=== Playlist ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;playlist&amp;quot;&amp;lt;/tt&amp;gt; mode supports the following commands:&lt;br /&gt;
* &amp;lt;tt&amp;gt;id=[track_id]&amp;lt;/tt&amp;gt; - Halt playback of any current track and switch to the track with the specified id. Returns a &amp;lt;tt&amp;gt;800&amp;lt;/tt&amp;gt; fault code if &amp;lt;tt&amp;gt;[track_id]&amp;lt;/tt&amp;gt; is not valid.&lt;br /&gt;
* &amp;lt;tt&amp;gt;index=[playlist_index]&amp;lt;/tt&amp;gt; - Halt playback of the current track and switch to the track with the specified index. Returns a &amp;lt;tt&amp;gt;802&amp;lt;/tt&amp;gt; fault code if the index is beyond the end of the playlist.&lt;br /&gt;
* &amp;lt;tt&amp;gt;track={&amp;quot;uri&amp;quot;:&amp;quot;track_uri&amp;quot;,&amp;quot;metadata&amp;quot;:&amp;quot;didl_lite&amp;quot;}&amp;lt;/tt&amp;gt; - load the specified track at the end of the current Playlist and play it next.&lt;br /&gt;
&lt;br /&gt;
=== Radio ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;radio&amp;quot;&amp;lt;/tt&amp;gt; mode supports the following command:&lt;br /&gt;
* &amp;lt;tt&amp;gt;id=[preset_id]&amp;lt;/tt&amp;gt; – Start playing the specified preset.  Returns a &amp;lt;tt&amp;gt;800&amp;lt;/tt&amp;gt; fault code if &amp;lt;tt&amp;gt;[preset_id]&amp;lt;/tt&amp;gt; does not match a current preset&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;quot;Radio-Single&amp;quot;&amp;lt;/tt&amp;gt; mode supports the following command:&lt;br /&gt;
* &amp;lt;tt&amp;gt;track={&amp;quot;uri&amp;quot;:&amp;quot;track_uri&amp;quot;,&amp;quot;metadata&amp;quot;:&amp;quot;didl_lite&amp;quot;}&amp;lt;/tt&amp;gt; - load the specified track.&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhMedia</id>
		<title>OhMedia</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhMedia"/>
				<updated>2021-06-10T15:49:21Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Reference Implementations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=What is ohMedia?=&lt;br /&gt;
&lt;br /&gt;
OpenHome Media (ohMedia) is an open standard for networked audio devices in the home.  Devices can implement ohMedia in place of, or alongside of, the UPnP Forum’s AV standards.  It offers a number of advantages over the UPnP Forum's AV standards.&lt;br /&gt;
&lt;br /&gt;
* Easier to program against.&lt;br /&gt;
** UPnP forum services have large numbers of optional features.  While this makes it easy for device manufacturers to implement a service, it is hard to write control points and interoperability between devices becomes poor.  ohMedia uses options sparingly, typically at a service level.  This enables clear, consistent behaviour across devices from different manufacturers.&lt;br /&gt;
* Better support for playlists&lt;br /&gt;
** Playlists are stored on the renderer, allowing playback to continue when the control point leaves the network (e.g. your tablet goes to sleep, runs out of battery, or leaves the wifi zone).&lt;br /&gt;
** Multiple control points are supported.  A second controller can discover and display a playlist setup by a different device.  Edits to the playlist from either controller will be immediately reflected in the other.&lt;br /&gt;
** Storing playlists on the renderer also allows for gapless playback, avoiding gaps between tracks that were intended to merge seamlessly. This is particularly important for live albums and classical music.&lt;br /&gt;
* Control the room, not just a device&lt;br /&gt;
** ohMedia topology algorithms allow multi-box systems to be easily managed from a single control point application&lt;br /&gt;
* Easy to share music&lt;br /&gt;
** The Songcast protocol allows an ohMedia renderer to share its content with any other ohMedia device or listen to content from another device. Synchronised audio can be played between any number of devices.&lt;br /&gt;
** Desktop songcast applications plus mobile support (Songcast app for Android; Airplay receiver for iOS) allows content from many other devices to be shared.&lt;br /&gt;
* Richer set of audio sources&lt;br /&gt;
** In addition to Playlist, Songcast and external digital and analogue inputs, internet radio and a receiver for Apple's AirPlay are also natively supported.&lt;br /&gt;
&lt;br /&gt;
= Developers =&lt;br /&gt;
If you are interested in ohMedia development, [[OhMediaDevelopers | further information is available]]&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Scd</id>
		<title>Av:Developer:Scd</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Scd"/>
				<updated>2019-12-13T10:08:34Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Overview */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Songcast Direct =&lt;br /&gt;
== Overview ==&lt;br /&gt;
Songcast Direct (SCD) can be used to send decoded audio from any computing device to an OpenHome device.  The Sender device is responsible for decoding audio to PCM, framing this in a simple protocol and making it available via a simple TCP server.  The Receiver pulls data from this server, giving the Receiver complete control of the audio clock.&lt;br /&gt;
&lt;br /&gt;
A Songcast Direct sender performs a broadly similar role to a Songcast sender.  Applications that perform their own decoding to PCM will find SCD is easier to integrate and offers higher audio performance:&lt;br /&gt;
* There is a constant TCP connection between sender and receiver, avoiding the need for application-level resend support&lt;br /&gt;
* It uses the clock of the receiver, allowing for higher quality playback if the sender is on a desktop computer&lt;br /&gt;
* It offers the receiver limited control over the stream – initially Transport (play / pause / stop) and Volume.  While the primary control UI may reside on the sender device, this allows for basic integration with any Ir handset for the receiver.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd ohPipeline] contains sample code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;WavSender&amp;lt;/tt&amp;gt; contains an example of a trivial SCD Sender, scanning a single directory and decoding then sending any WAV files it finds. (Note that compilation of this is currently disabled.  &amp;lt;tt&amp;gt;DirScanner::Run()&amp;lt;/tt&amp;gt; contains code from an experimental precursor to C++17's &amp;lt;tt&amp;gt;std::filesystem::directory_iterator&amp;lt;/tt&amp;gt;.  Current code is compatible with VS2013; it should only require a couple of lines of change to make this compile against any more recent compiler.)&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd Scd] and [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd/Sender Sender] directories should be usable without any change.  It will be possible to write a commercial quality sender using the &amp;lt;tt&amp;gt;ScdSender&amp;lt;/tt&amp;gt; library, passing audio into &amp;lt;tt&amp;gt;IScdSupply&amp;lt;/tt&amp;gt; and relying on the configuration of &amp;lt;tt&amp;gt;ScdMsgFactory&amp;lt;/tt&amp;gt; to determine how much audio is buffered by the Sender.&lt;br /&gt;
&lt;br /&gt;
Sample code demonstrating how a Sender can control a Receiver via ODP is coming soon.  For now, see [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP tests] for a basic example.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
=== SSDP ===&lt;br /&gt;
First search for &amp;lt;tt&amp;gt;av-openhome-org:service:Product:2&amp;lt;/tt&amp;gt; then either&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Attributes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;Transport&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Transport&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;SourceXml&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; for a source with &amp;lt;tt&amp;gt;Type&amp;lt;/tt&amp;gt; of &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== mDNS ===&lt;br /&gt;
Search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; service to identify ODP endpoint&lt;br /&gt;
&lt;br /&gt;
== Control ==&lt;br /&gt;
Control of the Receiver is out of band, via the standard [[OhMediaDevelopers#Network_Services | OpenHome network APIs]].  These are available over UPnP or [[OhMediaDevelopers#ODP | ODP]] (a single connected socket).&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
The protocol used for communication between Sender and Receiver contains the following message types:&lt;br /&gt;
{|&lt;br /&gt;
! '''Type'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
! '''Sent by'''&lt;br /&gt;
|-&lt;br /&gt;
| Ready&lt;br /&gt;
| Signals availability and version support to other party&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataDidl &lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataOh&lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Format&lt;br /&gt;
| Format for the following (PCM) audio. Must be sent before any audio.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| FormatDsd&lt;br /&gt;
| Format for the following (DSD) audio. Must be sent before any audio.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Audio&lt;br /&gt;
| Decoded audio.  Can only be sent after a &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; message describing  its sample rate etc.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextDidl&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextOh&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].  Note that a uri does not need to be specified.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Halt&lt;br /&gt;
| Indicates that a break in audio follows.  E.g. at the end of a track with no further tracks to be played, or when the Sender has paused.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Disconnect&lt;br /&gt;
| Indicates that the originator of the message is closing its SCD session. No further audio will be available. The message receiver should disconnect its socket.&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| Seek&lt;br /&gt;
| Indicates that the Receiver wants to jump to a different point in the current track.&amp;lt;br&amp;gt;Is only sent for tracks that the Sender has indicated support seeking.&lt;br /&gt;
| Receiver&lt;br /&gt;
|-&lt;br /&gt;
| Skip&lt;br /&gt;
| Indicates that the Receiver wants to immediately jump to the next or previous track.&lt;br /&gt;
| Receiver&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A SCD session is initiated by the Sender.  It instantiates a simple TCP server then instructs the Receiver to start playing from it.&lt;br /&gt;
&lt;br /&gt;
The Receiver connects to the Sender and sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, indicating the protocol version it supports.  If the Sender is compatible with this version, it responds with a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the same version.  Otherwise, the Sender sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the version it supports.  If the Receiver cannot support this version, it must close the connection.&lt;br /&gt;
&lt;br /&gt;
After sending a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, the Sender should send either &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; (if it has nothing to send yet) or one of &amp;lt;tt&amp;gt;MetadataDidl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;MetadataOh&amp;lt;/tt&amp;gt; plus &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt;.  The order of &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; versus &amp;lt;tt&amp;gt;Metadata*&amp;lt;/tt&amp;gt; is not important.&lt;br /&gt;
&lt;br /&gt;
After this, the Sender should then send &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.  Any number of &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; messages can be sent until the end of the stream is reached.  &amp;lt;tt&amp;gt;Metatext&amp;lt;/tt&amp;gt; messages (either &amp;lt;tt&amp;gt;Didl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Oh&amp;lt;/tt&amp;gt;) may be interleaved with &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; message implies that a break in audio may follow.  If this break is during a stream, the Sender must have applied attenuation to samples immediately before this to avoid any audio artifacts at the break in transmission.  Senders which cannot do this should implement pausing of streams using the Transport.Pause control API instead.&lt;br /&gt;
&lt;br /&gt;
The details of the wire protocol are shown below.  Note that all multi-byte integer values are big endian.&lt;br /&gt;
{|&lt;br /&gt;
! '''Bytes'''&lt;br /&gt;
! '''Name'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| '''Header'''&lt;br /&gt;
|&lt;br /&gt;
| Prefixes to all messages below&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Signature&lt;br /&gt;
| 0x73, 0x63, 0x64,0x20 ('scd ')&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Type&lt;br /&gt;
| The type of message:&lt;br /&gt;
* 0 – Ready&lt;br /&gt;
* 1 – MetadataDidl&lt;br /&gt;
* 2 - MetaDataOh&lt;br /&gt;
* 3 – Format&lt;br /&gt;
* 4 – FormatDsd&lt;br /&gt;
* 5 – Audio&lt;br /&gt;
* 7 – MetatextDidl&lt;br /&gt;
* 8 – MetatextOh&lt;br /&gt;
* 9 – Halt&lt;br /&gt;
* 10 – Disconnect&lt;br /&gt;
* 11 – Seek&lt;br /&gt;
* 12 – Skip&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Length&lt;br /&gt;
| Length in bytes of the whole message including this header&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Reserved&lt;br /&gt;
| Unused, reserved for future use&lt;br /&gt;
|-&lt;br /&gt;
| '''Ready'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Major Version&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Minor Version&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| TrackUriLength&lt;br /&gt;
| Length, in bytes, of the track URI&lt;br /&gt;
|-&lt;br /&gt;
| m&lt;br /&gt;
| TrackUri&lt;br /&gt;
| The track URI, where m = TrackUriLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| MetadataLength&lt;br /&gt;
| Length, in bytes, of the track metadata, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metadata&lt;br /&gt;
| The track metadata, where n = MetadataLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metadata element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metadata element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metadata elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Format'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| BitDepth&lt;br /&gt;
| Bit depth of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| SampleRate&lt;br /&gt;
| Sample rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Channels&lt;br /&gt;
| Number of channels of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| BitRate&lt;br /&gt;
| Bit rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SampleStart&lt;br /&gt;
| Sample position of the first sample in the next &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; message&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SamplesTotal&lt;br /&gt;
| Total number of samples in the following audio (requirement for this to be confirmed)&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Flags&lt;br /&gt;
|&lt;br /&gt;
* Bit 0 - Seekable&lt;br /&gt;
* Bit 1 - Lossless&lt;br /&gt;
* Bit 2 - Live (content generated upstream of the Sender, e.g. internet radio)&lt;br /&gt;
* Bit 3 - Broadcastable (whether the Receiver is allowed to offer the following audio via any multi-room protocols&lt;br /&gt;
* Bits 4-7 - Reserved.  Must be zero.&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| CodecNameLength&lt;br /&gt;
| Length, in bytes, of the codec name&lt;br /&gt;
|-&lt;br /&gt;
| r&lt;br /&gt;
| CodecName&lt;br /&gt;
| The codec name, where r = CodecNameLength&lt;br /&gt;
|-&lt;br /&gt;
| '''FormatDsd'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| SampleRate&lt;br /&gt;
| Sample rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Channels&lt;br /&gt;
| Number of channels of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| SampleBlockBits&lt;br /&gt;
| Block size (in bits) of DSD data.  2 for stereo where left/right channels are interleaved, 16 for stereo with one byte of left subsamples followed by one byte of right subsamples, etc.&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SampleStart&lt;br /&gt;
| Sample position of the first sample in the next &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; message&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SamplesTotal&lt;br /&gt;
| Total number of samples in the following audio (requirement for this to be confirmed)&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Flags&lt;br /&gt;
|&lt;br /&gt;
* Bit 0 - Seekable&lt;br /&gt;
* Bit 1-2 - Reserved.  Must be zero.&lt;br /&gt;
* Bit 3 - Broadcastable (whether the Receiver is allowed to offer the following audio via any multi-room protocols&lt;br /&gt;
* Bits 4-7 - Reserved.  Must be zero.&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| CodecNameLength&lt;br /&gt;
| Length, in bytes, of the codec name&lt;br /&gt;
|-&lt;br /&gt;
| r&lt;br /&gt;
| CodecName&lt;br /&gt;
| The codec name, where r = CodecNameLength&lt;br /&gt;
|-&lt;br /&gt;
| '''Audio'''&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| NumSamples&lt;br /&gt;
| The number of audio samples in this message&lt;br /&gt;
|-&lt;br /&gt;
| s&lt;br /&gt;
| AudioData&lt;br /&gt;
| Audio data.  Where s = NumSamples * (BitDepth/8) * NumChannels.&amp;lt;br&amp;gt;Multi-channel audio must supply data sample at a time, with left channel first.  Audio is packed (i.e. no padding bytes rounding samples up to 32-bit boundaries) and big endian.&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Metatext Length&lt;br /&gt;
| Length, in bytes, of the metatext, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metatext&lt;br /&gt;
| The metatext, where n = MetatextLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metatext element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metatext element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metatext elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Halt'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Disconnect'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Seek'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|-&lt;br /&gt;
| '''Skip'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2019-05-17T15:45:14Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Rev protocol version (addition of device id and service domains in various messages)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
=== Framing ===&lt;br /&gt;
Each message, in either direction, is a JSON object followed by a newline (&amp;lt;tt&amp;gt;'\n'&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Announcement ===&lt;br /&gt;
When a client connects, a device announces its capabilities:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;:&amp;quot;announcement&amp;quot;,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;:3,&lt;br /&gt;
        &amp;quot;devices&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;:&amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds, MediaRenderer, ZoneSetup, ZoneSource, ZoneReceiver&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service1&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service2&amp;quot;, &amp;quot;version&amp;quot;:2 },&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;xyz.com&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service3&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds, MediaRenderer, ZoneSetup, ZoneSource, ZoneReceiver&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service4&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;xyz.com&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service5&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Control ===&lt;br /&gt;
The control point can invoke an action on a device as follows.  This will block until a response is sent.  Note that it is possible that the control point may receive other messages (e.g. &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt; - see below) before the action response.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each input argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;action&amp;quot;,&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;domain&amp;quot;: &amp;quot;xyz.com&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 1 },&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;action_name&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
            ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;userAgent&amp;quot;:&amp;quot;optional client identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation is successful.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each output argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation fails:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Eventing ===&lt;br /&gt;
Subscribe to a particular service.  On successful completion, the device will send out unsolicited messages (with type &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt;) whenever one or more evented properties of a service change.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;id&amp;quot;, &amp;quot;udn&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 },&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request succeeds.  The subscription id (sid) will be included in all later evented updates for this subscription.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request fails.  No later evented updates will be sent.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;id&amp;quot;, &amp;quot;udn&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Unsubscribe (halt a particular stream of evented updates).&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when an unsubscribe completes.  No evented updates for this subscription will be sent after this.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A device will send the following whenever one or more evented properties change on a service with an active subscription.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each property will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for the associated &amp;lt;tt&amp;gt;stateVariable&amp;lt;/tt&amp;gt; in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;notify&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2019-05-17T13:58:23Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Include udn and service domain for subscription request / respose&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
=== Framing ===&lt;br /&gt;
Each message, in either direction, is a JSON object followed by a newline (&amp;lt;tt&amp;gt;'\n'&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Announcement ===&lt;br /&gt;
When a client connects, a device announces its capabilities:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;:&amp;quot;announcement&amp;quot;,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;:2,&lt;br /&gt;
        &amp;quot;devices&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;:&amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds, MediaRenderer, ZoneSetup, ZoneSource, ZoneReceiver&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service1&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service2&amp;quot;, &amp;quot;version&amp;quot;:2 },&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;xyz.com&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service3&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds, MediaRenderer, ZoneSetup, ZoneSource, ZoneReceiver&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service4&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;xyz.com&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service5&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Control ===&lt;br /&gt;
The control point can invoke an action on a device as follows.  This will block until a response is sent.  Note that it is possible that the control point may receive other messages (e.g. &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt; - see below) before the action response.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each input argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;action&amp;quot;,&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;domain&amp;quot;: &amp;quot;xyz.com&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 1 },&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;action_name&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
            ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;userAgent&amp;quot;:&amp;quot;optional client identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation is successful.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each output argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation fails:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Eventing ===&lt;br /&gt;
Subscribe to a particular service.  On successful completion, the device will send out unsolicited messages (with type &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt;) whenever one or more evented properties of a service change.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;id&amp;quot;, &amp;quot;udn&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 },&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request succeeds.  The subscription id (sid) will be included in all later evented updates for this subscription.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request fails.  No later evented updates will be sent.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;id&amp;quot;, &amp;quot;udn&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Unsubscribe (halt a particular stream of evented updates).&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when an unsubscribe completes.  No evented updates for this subscription will be sent after this.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A device will send the following whenever one or more evented properties change on a service with an active subscription.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each property will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for the associated &amp;lt;tt&amp;gt;stateVariable&amp;lt;/tt&amp;gt; in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;notify&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2019-05-17T13:56:47Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Optionally, specify udn.  Include domain in service description.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
=== Framing ===&lt;br /&gt;
Each message, in either direction, is a JSON object followed by a newline (&amp;lt;tt&amp;gt;'\n'&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Announcement ===&lt;br /&gt;
When a client connects, a device announces its capabilities:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;:&amp;quot;announcement&amp;quot;,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;:2,&lt;br /&gt;
        &amp;quot;devices&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;:&amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds, MediaRenderer, ZoneSetup, ZoneSource, ZoneReceiver&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service1&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service2&amp;quot;, &amp;quot;version&amp;quot;:2 },&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;xyz.com&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service3&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds, MediaRenderer, ZoneSetup, ZoneSource, ZoneReceiver&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service4&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;xyz.com&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service5&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Control ===&lt;br /&gt;
The control point can invoke an action on a device as follows.  This will block until a response is sent.  Note that it is possible that the control point may receive other messages (e.g. &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt; - see below) before the action response.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each input argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;action&amp;quot;,&lt;br /&gt;
        &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;domain&amp;quot;: &amp;quot;xyz.com&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 1 },&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;action_name&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
            ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;userAgent&amp;quot;:&amp;quot;optional client identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation is successful.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each output argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation fails:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Eventing ===&lt;br /&gt;
Subscribe to a particular service.  On successful completion, the device will send out unsolicited messages (with type &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt;) whenever one or more evented properties of a service change.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 },&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request succeeds.  The subscription id (sid) will be included in all later evented updates for this subscription.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request fails.  No later evented updates will be sent.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Unsubscribe (halt a particular stream of evented updates).&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when an unsubscribe completes.  No evented updates for this subscription will be sent after this.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A device will send the following whenever one or more evented properties change on a service with an active subscription.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each property will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for the associated &amp;lt;tt&amp;gt;stateVariable&amp;lt;/tt&amp;gt; in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;notify&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2019-05-17T13:55:36Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Include domain in service description&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
=== Framing ===&lt;br /&gt;
Each message, in either direction, is a JSON object followed by a newline (&amp;lt;tt&amp;gt;'\n'&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Announcement ===&lt;br /&gt;
When a client connects, a device announces its capabilities:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;:&amp;quot;announcement&amp;quot;,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;:2,&lt;br /&gt;
        &amp;quot;devices&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;:&amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds, MediaRenderer, ZoneSetup, ZoneSource, ZoneReceiver&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service1&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service2&amp;quot;, &amp;quot;version&amp;quot;:2 },&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;xyz.com&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service3&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds, MediaRenderer, ZoneSetup, ZoneSource, ZoneReceiver&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;abc.org&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service4&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;domain&amp;quot;: &amp;quot;xyz.com&amp;quot;, &amp;quot;name&amp;quot;:&amp;quot;service5&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Control ===&lt;br /&gt;
The control point can invoke an action on a device as follows.  This will block until a response is sent.  Note that it is possible that the control point may receive other messages (e.g. &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt; - see below) before the action response.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each input argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;action&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 1 },&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;action_name&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
            ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;userAgent&amp;quot;:&amp;quot;optional client identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation is successful.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each output argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation fails:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Eventing ===&lt;br /&gt;
Subscribe to a particular service.  On successful completion, the device will send out unsolicited messages (with type &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt;) whenever one or more evented properties of a service change.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 },&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request succeeds.  The subscription id (sid) will be included in all later evented updates for this subscription.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request fails.  No later evented updates will be sent.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Unsubscribe (halt a particular stream of evented updates).&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when an unsubscribe completes.  No evented updates for this subscription will be sent after this.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A device will send the following whenever one or more evented properties change on a service with an active subscription.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each property will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for the associated &amp;lt;tt&amp;gt;stateVariable&amp;lt;/tt&amp;gt; in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;notify&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2019-02-27T15:47:06Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Announcement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
=== Framing ===&lt;br /&gt;
Each message, in either direction, is a JSON object followed by a newline (&amp;lt;tt&amp;gt;'\n'&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Announcement ===&lt;br /&gt;
When a client connects, a device announces its capabilities:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;:&amp;quot;announcement&amp;quot;,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;:2,&lt;br /&gt;
        &amp;quot;devices&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;:&amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds, MediaRenderer, ZoneSetup, ZoneSource, ZoneReceiver&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service1&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service2&amp;quot;, &amp;quot;version&amp;quot;:2 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service3&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds, MediaRenderer, ZoneSetup, ZoneSource, ZoneReceiver&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service4&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service5&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Control ===&lt;br /&gt;
The control point can invoke an action on a device as follows.  This will block until a response is sent.  Note that it is possible that the control point may receive other messages (e.g. &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt; - see below) before the action response.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each input argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;action&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 1 },&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;action_name&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
            ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;userAgent&amp;quot;:&amp;quot;optional client identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation is successful.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each output argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation fails:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Eventing ===&lt;br /&gt;
Subscribe to a particular service.  On successful completion, the device will send out unsolicited messages (with type &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt;) whenever one or more evented properties of a service change.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 },&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request succeeds.  The subscription id (sid) will be included in all later evented updates for this subscription.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request fails.  No later evented updates will be sent.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Unsubscribe (halt a particular stream of evented updates).&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when an unsubscribe completes.  No evented updates for this subscription will be sent after this.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A device will send the following whenever one or more evented properties change on a service with an active subscription.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each property will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for the associated &amp;lt;tt&amp;gt;stateVariable&amp;lt;/tt&amp;gt; in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;notify&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-21T09:53:34Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* CalmRadio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= (Linn) Kazoo Server =&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Only supported in a list pin&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Server's Udn&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| me&lt;br /&gt;
| Endpoint Id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
| browse&lt;br /&gt;
| Item id&lt;br /&gt;
| Performs a browse query with the given item id. Can't contain list parameter&lt;br /&gt;
|-&lt;br /&gt;
| list&lt;br /&gt;
| Tag id&lt;br /&gt;
| Performs a list query with given tag id. Can't contain a browse parameter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uris: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  // Browse pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;browse=[item id]&amp;amp;response=[response type]&lt;br /&gt;
  &lt;br /&gt;
  // List pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;list=[item id]&amp;amp;response[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tidal =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Tidal track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Tidal Content ==&lt;br /&gt;
&lt;br /&gt;
For other Tidal content the pin will provide a link to the Tidal API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Tidal API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Qobuz =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Qobuz track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Qobuz Content ==&lt;br /&gt;
&lt;br /&gt;
For other Qobuz content the pin will provide a link to the Qobuz API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Qobuz API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TuneIn =&lt;br /&gt;
== Stations ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn station pin should play the station from the TuneIn link specified in the pin uri.&lt;br /&gt;
&amp;lt;br&amp;gt;Note that the pin's title and artwork uri will be presented as track metadata by the [[Av:Developer:InfoService | Info]] service.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shows / Podcasts ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn show/podcast pin should play the most recent episode as reported by the TuneIn link specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
| Latest episode&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tuneinlist&lt;br /&gt;
| All episodes&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Show/podcast link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://podcast?path=[stream]&lt;br /&gt;
  tuneinlist://podcast?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Radio Preset =&lt;br /&gt;
Play a radio preset by index:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  radio://preset?id=[index]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= iTunes Podcast =&lt;br /&gt;
Play either the latest episode from a podcast or load a playlist with the last N episodes&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| itunes&lt;br /&gt;
| Latest episode only&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| ituneslist&lt;br /&gt;
| Load all of the episode list&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| iTunes podcast id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  itunes://podcast?id=[identifier]&lt;br /&gt;
  ituneslist://podcast?id=[identifier]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Sources =&lt;br /&gt;
&lt;br /&gt;
A source pin should switch to the source matching the system name specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| transport&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| source&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| The system name of the source&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Udn of the device to which the source belongs&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  transport://source?id=[system name]&amp;amp;udn=[device udn]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= CalmRadio =&lt;br /&gt;
&lt;br /&gt;
A CalmRadio pin should play the stream specified in the pin uri&lt;br /&gt;
&amp;lt;br&amp;gt;Note that the pin's title and artwork uri will be presented as track metadata by the [[Av:Developer:InfoService | Info]] service.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| calmradio&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  calmradio://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Url =&lt;br /&gt;
Play a hard-coded url.&lt;br /&gt;
&amp;lt;br&amp;gt;Note that the pin's title and artwork uri will be presented as track metadata by the [[Av:Developer:InfoService | Info]] service.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  url://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-21T09:53:27Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Url */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= (Linn) Kazoo Server =&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Only supported in a list pin&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Server's Udn&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| me&lt;br /&gt;
| Endpoint Id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
| browse&lt;br /&gt;
| Item id&lt;br /&gt;
| Performs a browse query with the given item id. Can't contain list parameter&lt;br /&gt;
|-&lt;br /&gt;
| list&lt;br /&gt;
| Tag id&lt;br /&gt;
| Performs a list query with given tag id. Can't contain a browse parameter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uris: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  // Browse pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;browse=[item id]&amp;amp;response=[response type]&lt;br /&gt;
  &lt;br /&gt;
  // List pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;list=[item id]&amp;amp;response[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tidal =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Tidal track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Tidal Content ==&lt;br /&gt;
&lt;br /&gt;
For other Tidal content the pin will provide a link to the Tidal API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Tidal API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Qobuz =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Qobuz track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Qobuz Content ==&lt;br /&gt;
&lt;br /&gt;
For other Qobuz content the pin will provide a link to the Qobuz API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Qobuz API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TuneIn =&lt;br /&gt;
== Stations ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn station pin should play the station from the TuneIn link specified in the pin uri.&lt;br /&gt;
&amp;lt;br&amp;gt;Note that the pin's title and artwork uri will be presented as track metadata by the [[Av:Developer:InfoService | Info]] service.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shows / Podcasts ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn show/podcast pin should play the most recent episode as reported by the TuneIn link specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
| Latest episode&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tuneinlist&lt;br /&gt;
| All episodes&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Show/podcast link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://podcast?path=[stream]&lt;br /&gt;
  tuneinlist://podcast?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Radio Preset =&lt;br /&gt;
Play a radio preset by index:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  radio://preset?id=[index]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= iTunes Podcast =&lt;br /&gt;
Play either the latest episode from a podcast or load a playlist with the last N episodes&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| itunes&lt;br /&gt;
| Latest episode only&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| ituneslist&lt;br /&gt;
| Load all of the episode list&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| iTunes podcast id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  itunes://podcast?id=[identifier]&lt;br /&gt;
  ituneslist://podcast?id=[identifier]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Sources =&lt;br /&gt;
&lt;br /&gt;
A source pin should switch to the source matching the system name specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| transport&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| source&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| The system name of the source&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Udn of the device to which the source belongs&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  transport://source?id=[system name]&amp;amp;udn=[device udn]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= CalmRadio =&lt;br /&gt;
&lt;br /&gt;
A CalmRadio pin should play the stream specified in the pin uri&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| calmradio&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  calmradio://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Url =&lt;br /&gt;
Play a hard-coded url.&lt;br /&gt;
&amp;lt;br&amp;gt;Note that the pin's title and artwork uri will be presented as track metadata by the [[Av:Developer:InfoService | Info]] service.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  url://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-21T09:53:19Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Stations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= (Linn) Kazoo Server =&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Only supported in a list pin&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Server's Udn&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| me&lt;br /&gt;
| Endpoint Id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
| browse&lt;br /&gt;
| Item id&lt;br /&gt;
| Performs a browse query with the given item id. Can't contain list parameter&lt;br /&gt;
|-&lt;br /&gt;
| list&lt;br /&gt;
| Tag id&lt;br /&gt;
| Performs a list query with given tag id. Can't contain a browse parameter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uris: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  // Browse pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;browse=[item id]&amp;amp;response=[response type]&lt;br /&gt;
  &lt;br /&gt;
  // List pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;list=[item id]&amp;amp;response[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tidal =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Tidal track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Tidal Content ==&lt;br /&gt;
&lt;br /&gt;
For other Tidal content the pin will provide a link to the Tidal API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Tidal API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Qobuz =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Qobuz track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Qobuz Content ==&lt;br /&gt;
&lt;br /&gt;
For other Qobuz content the pin will provide a link to the Qobuz API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Qobuz API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TuneIn =&lt;br /&gt;
== Stations ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn station pin should play the station from the TuneIn link specified in the pin uri.&lt;br /&gt;
&amp;lt;br&amp;gt;Note that the pin's title and artwork uri will be presented as track metadata by the [[Av:Developer:InfoService | Info]] service.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shows / Podcasts ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn show/podcast pin should play the most recent episode as reported by the TuneIn link specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
| Latest episode&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tuneinlist&lt;br /&gt;
| All episodes&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Show/podcast link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://podcast?path=[stream]&lt;br /&gt;
  tuneinlist://podcast?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Radio Preset =&lt;br /&gt;
Play a radio preset by index:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  radio://preset?id=[index]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= iTunes Podcast =&lt;br /&gt;
Play either the latest episode from a podcast or load a playlist with the last N episodes&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| itunes&lt;br /&gt;
| Latest episode only&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| ituneslist&lt;br /&gt;
| Load all of the episode list&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| iTunes podcast id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  itunes://podcast?id=[identifier]&lt;br /&gt;
  ituneslist://podcast?id=[identifier]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Sources =&lt;br /&gt;
&lt;br /&gt;
A source pin should switch to the source matching the system name specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| transport&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| source&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| The system name of the source&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Udn of the device to which the source belongs&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  transport://source?id=[system name]&amp;amp;udn=[device udn]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= CalmRadio =&lt;br /&gt;
&lt;br /&gt;
A CalmRadio pin should play the stream specified in the pin uri&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| calmradio&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  calmradio://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Url =&lt;br /&gt;
Play a hard-coded url&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  url://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-21T09:50:16Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= (Linn) Kazoo Server =&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Only supported in a list pin&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Server's Udn&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| me&lt;br /&gt;
| Endpoint Id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
| browse&lt;br /&gt;
| Item id&lt;br /&gt;
| Performs a browse query with the given item id. Can't contain list parameter&lt;br /&gt;
|-&lt;br /&gt;
| list&lt;br /&gt;
| Tag id&lt;br /&gt;
| Performs a list query with given tag id. Can't contain a browse parameter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uris: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  // Browse pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;browse=[item id]&amp;amp;response=[response type]&lt;br /&gt;
  &lt;br /&gt;
  // List pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;list=[item id]&amp;amp;response[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tidal =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Tidal track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Tidal Content ==&lt;br /&gt;
&lt;br /&gt;
For other Tidal content the pin will provide a link to the Tidal API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Tidal API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Qobuz =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Qobuz track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Qobuz Content ==&lt;br /&gt;
&lt;br /&gt;
For other Qobuz content the pin will provide a link to the Qobuz API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Qobuz API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TuneIn =&lt;br /&gt;
== Stations ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn station pin should play the station from the TuneIn link specified in the pin uri&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shows / Podcasts ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn show/podcast pin should play the most recent episode as reported by the TuneIn link specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
| Latest episode&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tuneinlist&lt;br /&gt;
| All episodes&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Show/podcast link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://podcast?path=[stream]&lt;br /&gt;
  tuneinlist://podcast?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Radio Preset =&lt;br /&gt;
Play a radio preset by index:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  radio://preset?id=[index]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= iTunes Podcast =&lt;br /&gt;
Play either the latest episode from a podcast or load a playlist with the last N episodes&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| itunes&lt;br /&gt;
| Latest episode only&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| ituneslist&lt;br /&gt;
| Load all of the episode list&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| iTunes podcast id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  itunes://podcast?id=[identifier]&lt;br /&gt;
  ituneslist://podcast?id=[identifier]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Sources =&lt;br /&gt;
&lt;br /&gt;
A source pin should switch to the source matching the system name specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| transport&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| source&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| The system name of the source&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Udn of the device to which the source belongs&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  transport://source?id=[system name]&amp;amp;udn=[device udn]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= CalmRadio =&lt;br /&gt;
&lt;br /&gt;
A CalmRadio pin should play the stream specified in the pin uri&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| calmradio&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  calmradio://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Url =&lt;br /&gt;
Play a hard-coded url&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  url://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-21T09:49:10Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Shows / Podcasts */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= (Linn) Kazoo Server =&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Only supported in a list pin&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Server's Udn&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| me&lt;br /&gt;
| Endpoint Id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
| browse&lt;br /&gt;
| Item id&lt;br /&gt;
| Performs a browse query with the given item id. Can't contain list parameter&lt;br /&gt;
|-&lt;br /&gt;
| list&lt;br /&gt;
| Tag id&lt;br /&gt;
| Performs a list query with given tag id. Can't contain a browse parameter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uris: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  // Browse pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;browse=[item id]&amp;amp;response=[response type]&lt;br /&gt;
  &lt;br /&gt;
  // List pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;list=[item id]&amp;amp;response[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tidal =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Tidal track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Tidal Content ==&lt;br /&gt;
&lt;br /&gt;
For other Tidal content the pin will provide a link to the Tidal API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Tidal API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Qobuz =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Qobuz track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Qobuz Content ==&lt;br /&gt;
&lt;br /&gt;
For other Qobuz content the pin will provide a link to the Qobuz API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Qobuz API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TuneIn =&lt;br /&gt;
== Stations ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn station pin should play the station from the TuneIn link specified in the pin uri&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shows / Podcasts ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn show/podcast pin should play the most recent episode as reported by the TuneIn link specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
| Latest episode&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tuneinlist&lt;br /&gt;
| All episodes&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Show/podcast link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://podcast?path=[stream]&lt;br /&gt;
  tuneinlist://podcast?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Radio Preset =&lt;br /&gt;
Play a radio preset by index:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  radio://preset?id=[index]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= iTunes Podcast =&lt;br /&gt;
Play either the latest episode from a podcast or load a playlist with the last N episodes&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| itunes&lt;br /&gt;
| Latest episode only&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| ituneslist&lt;br /&gt;
| Load all of the episode list&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| iTunes podcast id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  itunes://podcast?id=[identifier]&lt;br /&gt;
  ituneslist://podcast?id=[identifier]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Sources =&lt;br /&gt;
&lt;br /&gt;
A source pin should switch to the source matching the system name specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| transport&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| source&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| The system name of the source&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Udn of the device to which the source belongs&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  transport://source?id=[system name]&amp;amp;udn=[device udn]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= CalmRadio =&lt;br /&gt;
&lt;br /&gt;
A CalmRadio pin should play the stream specified in the pin uri&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| calmradio&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  calmradio://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-21T09:48:12Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* iTunes Podcast */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= (Linn) Kazoo Server =&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Only supported in a list pin&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Server's Udn&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| me&lt;br /&gt;
| Endpoint Id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
| browse&lt;br /&gt;
| Item id&lt;br /&gt;
| Performs a browse query with the given item id. Can't contain list parameter&lt;br /&gt;
|-&lt;br /&gt;
| list&lt;br /&gt;
| Tag id&lt;br /&gt;
| Performs a list query with given tag id. Can't contain a browse parameter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uris: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  // Browse pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;browse=[item id]&amp;amp;response=[response type]&lt;br /&gt;
  &lt;br /&gt;
  // List pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;list=[item id]&amp;amp;response[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tidal =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Tidal track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Tidal Content ==&lt;br /&gt;
&lt;br /&gt;
For other Tidal content the pin will provide a link to the Tidal API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Tidal API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Qobuz =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Qobuz track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Qobuz Content ==&lt;br /&gt;
&lt;br /&gt;
For other Qobuz content the pin will provide a link to the Qobuz API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Qobuz API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TuneIn =&lt;br /&gt;
== Stations ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn station pin should play the station from the TuneIn link specified in the pin uri&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shows / Podcasts ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn show/podcast pin should play the most recent episode as reported by the TuneIn link specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Show/podcast link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://podcast?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Radio Preset =&lt;br /&gt;
Play a radio preset by index:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  radio://preset?id=[index]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= iTunes Podcast =&lt;br /&gt;
Play either the latest episode from a podcast or load a playlist with the last N episodes&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| itunes&lt;br /&gt;
| Latest episode only&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| ituneslist&lt;br /&gt;
| Load all of the episode list&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| iTunes podcast id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  itunes://podcast?id=[identifier]&lt;br /&gt;
  ituneslist://podcast?id=[identifier]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Sources =&lt;br /&gt;
&lt;br /&gt;
A source pin should switch to the source matching the system name specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| transport&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| source&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| The system name of the source&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Udn of the device to which the source belongs&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  transport://source?id=[system name]&amp;amp;udn=[device udn]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= CalmRadio =&lt;br /&gt;
&lt;br /&gt;
A CalmRadio pin should play the stream specified in the pin uri&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| calmradio&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  calmradio://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-20T17:07:44Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Sources + Calm Radio&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= (Linn) Kazoo Server =&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Only supported in a list pin&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Server's Udn&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| me&lt;br /&gt;
| Endpoint Id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
| browse&lt;br /&gt;
| Item id&lt;br /&gt;
| Performs a browse query with the given item id. Can't contain list parameter&lt;br /&gt;
|-&lt;br /&gt;
| list&lt;br /&gt;
| Tag id&lt;br /&gt;
| Performs a list query with given tag id. Can't contain a browse parameter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uris: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  // Browse pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;browse=[item id]&amp;amp;response=[response type]&lt;br /&gt;
  &lt;br /&gt;
  // List pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;list=[item id]&amp;amp;response[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tidal =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Tidal track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Tidal Content ==&lt;br /&gt;
&lt;br /&gt;
For other Tidal content the pin will provide a link to the Tidal API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Tidal API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Qobuz =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Qobuz track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Qobuz Content ==&lt;br /&gt;
&lt;br /&gt;
For other Qobuz content the pin will provide a link to the Qobuz API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Qobuz API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TuneIn =&lt;br /&gt;
== Stations ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn station pin should play the station from the TuneIn link specified in the pin uri&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shows / Podcasts ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn show/podcast pin should play the most recent episode as reported by the TuneIn link specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Show/podcast link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://podcast?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Radio Preset =&lt;br /&gt;
Play a radio preset by index:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  radio://preset?id=[index]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= iTunes Podcast =&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  itunes://podcast?id=[identifier]&lt;br /&gt;
  ituneslist://podcast?id=[identifier]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Sources =&lt;br /&gt;
&lt;br /&gt;
A source pin should switch to the source matching the system name specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| transport&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| source&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| The system name of the source&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Udn of the device to which the source belongs&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  transport://source?id=[system name]&amp;amp;udn=[device udn]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= CalmRadio =&lt;br /&gt;
&lt;br /&gt;
A CalmRadio pin should play the stream specified in the pin uri&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| calmradio&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  calmradio://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-20T17:03:37Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Radio + iTunes Podcast&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= (Linn) Kazoo Server =&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Only supported in a list pin&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Server's Udn&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| me&lt;br /&gt;
| Endpoint Id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
| browse&lt;br /&gt;
| Item id&lt;br /&gt;
| Performs a browse query with the given item id. Can't contain list parameter&lt;br /&gt;
|-&lt;br /&gt;
| list&lt;br /&gt;
| Tag id&lt;br /&gt;
| Performs a list query with given tag id. Can't contain a browse parameter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uris: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  // Browse pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;browse=[item id]&amp;amp;response=[response type]&lt;br /&gt;
  &lt;br /&gt;
  // List pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;list=[item id]&amp;amp;response[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tidal =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Tidal track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Tidal Content ==&lt;br /&gt;
&lt;br /&gt;
For other Tidal content the pin will provide a link to the Tidal API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Tidal API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Qobuz =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Qobuz track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Qobuz Content ==&lt;br /&gt;
&lt;br /&gt;
For other Qobuz content the pin will provide a link to the Qobuz API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Qobuz API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TuneIn =&lt;br /&gt;
== Stations ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn station pin should play the station from the TuneIn link specified in the pin uri&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shows / Podcasts ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn show/podcast pin should play the most recent episode as reported by the TuneIn link specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Show/podcast link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://podcast?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Radio Preset =&lt;br /&gt;
Play a radio preset by index:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  radio://preset?id=[index]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= iTunes Podcast =&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  itunes://podcast?id=[identifier]&lt;br /&gt;
  ituneslist://podcast?id=[identifier]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-20T17:00:30Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: TuneIn&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= (Linn) Kazoo Server =&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Only supported in a list pin&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Server's Udn&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| me&lt;br /&gt;
| Endpoint Id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
| browse&lt;br /&gt;
| Item id&lt;br /&gt;
| Performs a browse query with the given item id. Can't contain list parameter&lt;br /&gt;
|-&lt;br /&gt;
| list&lt;br /&gt;
| Tag id&lt;br /&gt;
| Performs a list query with given tag id. Can't contain a browse parameter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uris: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  // Browse pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;browse=[item id]&amp;amp;response=[response type]&lt;br /&gt;
  &lt;br /&gt;
  // List pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;list=[item id]&amp;amp;response[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tidal =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Tidal track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Tidal Content ==&lt;br /&gt;
&lt;br /&gt;
For other Tidal content the pin will provide a link to the Tidal API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Tidal API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Qobuz =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Qobuz track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Qobuz Content ==&lt;br /&gt;
&lt;br /&gt;
For other Qobuz content the pin will provide a link to the Qobuz API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Qobuz API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TuneIn =&lt;br /&gt;
== Stations ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn station pin should play the station from the TuneIn link specified in the pin uri&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| stream&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Radio stream link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://stream?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shows / Podcasts ==&lt;br /&gt;
&lt;br /&gt;
A TuneIn show/podcast pin should play the most recent episode as reported by the TuneIn link specified in the pin uri.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tunein&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| podcast&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Show/podcast link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tunein://podcast?path=[stream]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-20T16:47:34Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Tidal &amp;amp; Qobuz&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= (Linn) Kazoo Server =&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Only supported in a list pin&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Server's Udn&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| me&lt;br /&gt;
| Endpoint Id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
| browse&lt;br /&gt;
| Item id&lt;br /&gt;
| Performs a browse query with the given item id. Can't contain list parameter&lt;br /&gt;
|-&lt;br /&gt;
| list&lt;br /&gt;
| Tag id&lt;br /&gt;
| Performs a list query with given tag id. Can't contain a browse parameter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uris: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  // Browse pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;browse=[item id]&amp;amp;response=[response type]&lt;br /&gt;
  &lt;br /&gt;
  // List pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;list=[item id]&amp;amp;response[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tidal =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Tidal track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Tidal Content ==&lt;br /&gt;
&lt;br /&gt;
For other Tidal content the pin will provide a link to the Tidal API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| tidal&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Tidal API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  tidal://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Qobuz =&lt;br /&gt;
== Tracks ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
| type&lt;br /&gt;
| track&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| trackId&lt;br /&gt;
| Qobuz track id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://track?trackId=[id]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other Qobuz Content ==&lt;br /&gt;
&lt;br /&gt;
For other Qobuz content the pin will provide a link to the Qobuz API resource and a hint as to what you expect that resource to return. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| qobuz&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Requires response type of either albums, playlists&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| Qobuz API link&lt;br /&gt;
| Must to be url encoded&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uri:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  qobuz://[type]?path=[api link]&amp;amp;response=[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-20T13:46:55Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Kazoo Server&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= Supported Pins =&lt;br /&gt;
&lt;br /&gt;
== (Linn) Kazoo Server ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Only supported in a list pin&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Server's Udn&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| me&lt;br /&gt;
| Endpoint Id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
| browse&lt;br /&gt;
| Item id&lt;br /&gt;
| Performs a browse query with the given item id. Can't contain list parameter&lt;br /&gt;
|-&lt;br /&gt;
| list&lt;br /&gt;
| Tag id&lt;br /&gt;
| Performs a list query with given tag id. Can't contain a browse parameter&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example Uris: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  // Browse pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;browse=[item id]&amp;amp;response=[response type]&lt;br /&gt;
  &lt;br /&gt;
  // List pin&lt;br /&gt;
  openhome.me://[type]?udn=[device udn]&amp;amp;me=[endpoint id]&amp;amp;list=[item id]&amp;amp;response[response type]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-20T13:45:06Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= Supported Pins =&lt;br /&gt;
&lt;br /&gt;
== (Linn) Kazoo Server ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| genre&lt;br /&gt;
| Requires response type of either albums, playlists or tracks&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| container&lt;br /&gt;
| Only supported in a list pin&lt;br /&gt;
|-&lt;br /&gt;
| ''Query Parameters''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| udn&lt;br /&gt;
| Server's Udn&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| me&lt;br /&gt;
| Endpoint Id&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| response&lt;br /&gt;
| Response type&lt;br /&gt;
| See above&lt;br /&gt;
|-&lt;br /&gt;
| browse&lt;br /&gt;
| Item id&lt;br /&gt;
| Performs a browse query with the given item id. Can't contain list parameter&lt;br /&gt;
|-&lt;br /&gt;
| list&lt;br /&gt;
| Tag id&lt;br /&gt;
| Performs a list query with given tag id. Can't contain a browse parameter&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinInvokers</id>
		<title>Av:Developer:PinInvokers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinInvokers"/>
				<updated>2018-08-17T16:06:11Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Created page with &amp;quot;= Overview =  All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form:   &amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;:...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
All pins have a uri associated with them which is used by the pins service to interpret one or more playable items and must be in the following form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;lt;mode&amp;gt;://&amp;lt;type&amp;gt;?&amp;lt;pin specific query parameters&amp;gt;&amp;amp;version&amp;lt;pin version&amp;gt; &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; indicates which music provider will provide the playable content. Each has a number of query parameters which are outlined below. The pins service allows you to query which modes the device currently supports.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; describes what the pin is such as an artist, album or playlist.&lt;br /&gt;
&lt;br /&gt;
The current pin version is &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;. The version has been omitted from the examples below.&lt;br /&gt;
&lt;br /&gt;
= Supported Pins =&lt;br /&gt;
&lt;br /&gt;
== (Linn) Kazoo Server ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| mode&lt;br /&gt;
| openhome.me&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| album&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| artist&lt;br /&gt;
| Requires response type albums&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| playlist&lt;br /&gt;
| Requires response type tracks&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinsService</id>
		<title>Av:Developer:PinsService</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinsService"/>
				<updated>2018-08-17T09:14:44Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
A pin is a set of instructions to switch source or play one or more tracks on a device. Some pins will have wholly predictable results (e.g. switch to Analog2, play named playlist); others may be more dynamic (e.g. play the latest podcast from a given feed or a curated playlist of the week from a streaming service).&lt;br /&gt;
&lt;br /&gt;
The Pins service provides access both device-specific and account-wide pins. Both classes of pin can be read from or invoked on a device. Device-specific pins can also be edited; account-wide pins may be editable via a device but should also have edit APIs in the service or location that provides general account support.&lt;br /&gt;
&lt;br /&gt;
= Supported Content =&lt;br /&gt;
Reference code contains support for the following [[Av:Developer:PinInvokers | pinnable content]].&lt;br /&gt;
&lt;br /&gt;
= State Variables =&lt;br /&gt;
== DeviceMax ==&lt;br /&gt;
The maximum number of device-specific pins supported&lt;br /&gt;
&lt;br /&gt;
== AccountMax ==&lt;br /&gt;
The maximum number of account-wide pins supported&lt;br /&gt;
&lt;br /&gt;
== Modes ==&lt;br /&gt;
JSON array of strings identifying the different styles of pins supported&lt;br /&gt;
&lt;br /&gt;
== CloudConnected ==&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if a connection is available to cloud-backed master copy of account pins (i.e. when account pins are editable); &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
== IdArray ==&lt;br /&gt;
JSON array of identifiers (unsigned integer) for all pins. &lt;br /&gt;
&amp;lt;br&amp;gt;Device pins are listed first, followed by Account pins. i.e. array will always have &amp;lt;tt&amp;gt;DeviceMax&amp;lt;/tt&amp;gt; + &amp;lt;tt&amp;gt;AccountMax&amp;lt;/tt&amp;gt; entries. &lt;br /&gt;
&amp;lt;br&amp;gt;Identifiers will normally be unique; &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; is a special case which signifies an empty pin.&lt;br /&gt;
&lt;br /&gt;
= Actions =&lt;br /&gt;
== GetDeviceMax ==&lt;br /&gt;
Read the &amp;lt;tt&amp;gt;DeviceMax&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
== GetAccountMax ==&lt;br /&gt;
Read the &amp;lt;tt&amp;gt;AccountMax&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
== GetModes ==&lt;br /&gt;
Read the &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
== GetCloudConnected ==&lt;br /&gt;
Read the &amp;lt;tt&amp;gt;CloudConnected&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
== GetIdArray ==&lt;br /&gt;
Read the &amp;lt;tt&amp;gt;IdArray&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
== ReadList ==&lt;br /&gt;
Input: JSON integer array, specifying ids of pins to be read. &lt;br /&gt;
&amp;lt;br&amp;gt;Output: JSON array of pins&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {unsigned integer, unique across device &amp;amp; account pins},&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;where track(s) will be fetched from&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;instructs the device how to interpret the uri below&amp;quot;,&lt;br /&gt;
        &amp;quot;uri&amp;quot;: &amp;quot;absolute uri&amp;quot;,&lt;br /&gt;
        &amp;quot;title&amp;quot;: &amp;quot;Short text, may be user-visible&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Longer text, may be user-visible&amp;quot;,&lt;br /&gt;
        &amp;quot;artworkUri&amp;quot;: &amp;quot;absolute uri to image&amp;quot;,&lt;br /&gt;
        &amp;quot;shuffle&amp;quot;: {boolean}&lt;br /&gt;
    },&lt;br /&gt;
    { ... }&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== InvokeIndex ==&lt;br /&gt;
Invoke the pin at the specified index in &amp;lt;tt&amp;gt;IdArray&amp;lt;/tt&amp;gt;. This will stop anything that is currently playing and may clear any current playlist.&lt;br /&gt;
&lt;br /&gt;
== InvokeId ==&lt;br /&gt;
Invoke the pin with the specified id. This will stop anything that is currently playing and may clear any current playlist.&lt;br /&gt;
&lt;br /&gt;
== InvokeUri ==&lt;br /&gt;
Invoke a pin using data (mode, type, uri, shuffle) from a control point. Should be used by any control point that wants to determine which account to read pins from. (Note however that pins which themselves require cloud support to load cannot be loaded by the device - control points would have to load them directly into a playlist instead.) This will stop anything that is currently playing and may clear any current playlist.&lt;br /&gt;
&lt;br /&gt;
== SetDevice ==&lt;br /&gt;
Set a device pin, specifying the mode, type, uri, title, description, artworkUri and shuffle plus index into the set of device pins. &lt;br /&gt;
&amp;lt;br&amp;gt;Any pin currently assigned at the specified index will be replaced. &lt;br /&gt;
&amp;lt;br&amp;gt;Any playing content is unaffected (i.e. invoking then replacing a pin leaves the old representation of the pin playing). &lt;br /&gt;
index must be in the range &amp;lt;tt&amp;gt;[0..DeviceMax)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;Some errors are notified in response to this action. Success should only be assumed when an update is evented to IdArray showing a change in id at the specified index.&lt;br /&gt;
&lt;br /&gt;
== SetAccount ==&lt;br /&gt;
Set an account pin, specifying the mode, type, uri, title, description, artworkUri and shuffle plus index into the set of device pins. &lt;br /&gt;
&amp;lt;br&amp;gt;Any pin currently assigned at the specified index will be replaced. &lt;br /&gt;
&amp;lt;br&amp;gt;Any playing content is unaffected (i.e. invoking then replacing a pin leaves the old representation of the pin playing). &lt;br /&gt;
index must be in the range &amp;lt;tt&amp;gt;[0..AccountMax)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;Requests to update an account pin are proxied to a remote server so are likely to be slower and have greater chance of failure. &lt;br /&gt;
&amp;lt;br&amp;gt;Some errors are notified in response to this action. Success should only be assumed when an update is evented to &amp;lt;tt&amp;gt;IdArray&amp;lt;/tt&amp;gt; showing a change in id at &amp;lt;tt&amp;gt;DeviceMax + index&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Clear ==&lt;br /&gt;
Clear any content in the pin with the specified id. &lt;br /&gt;
&amp;lt;br&amp;gt;As with Set, changes to device pins are implemented locally; changes to account pins are proxied to a remote server. &lt;br /&gt;
&amp;lt;br&amp;gt;Some errors are notified in response to this action. Success should only be assumed when an update is evented to the sequence number for the specified id.&lt;br /&gt;
&lt;br /&gt;
== Swap ==&lt;br /&gt;
Swap contents of the 2 pins at the specified indices. &lt;br /&gt;
&amp;lt;br&amp;gt;Pins can only be swapped within either device or account lists.&lt;br /&gt;
&lt;br /&gt;
= Technical Details =&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
    Domain  : av.openhome.org&lt;br /&gt;
    Name    : Pins&lt;br /&gt;
    Version : 1&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Service Description (XML) ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;scpd xmlns=&amp;quot;urn:schemas-upnp-org:service-1-0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;specVersion&amp;gt;&lt;br /&gt;
    &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
    &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/specVersion&amp;gt;&lt;br /&gt;
  &amp;lt;actionList&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;GetDeviceMax&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;DeviceMax&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;DeviceMax&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;GetAccountMax&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;AccountMax&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;AccountMax&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;GetModes&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Modes&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;Modes&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;GetIdArray&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;IdArray&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;IdArray&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;GetCloudConnected&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CloudConnected&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CloudConnected&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;ReadList&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Ids&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;List&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;InvokeId&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Id&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;InvokeIndex&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Index&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;InvokeUri&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Mode&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Type&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Uri&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Bool&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SetDevice&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Index&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Mode&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Type&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Uri&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Title&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Description&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;ArtworkUri&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Bool&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SetAccount&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Index&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Mode&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Type&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Uri&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Title&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Description&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;ArtworkUri&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Bool&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Clear&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Id&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Swap&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Index1&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Index2&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
  &amp;lt;/actionList&amp;gt;&lt;br /&gt;
  &amp;lt;serviceStateTable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;DeviceMax&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;ui4&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;AccountMax&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;ui4&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Modes&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;string&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;IdArray&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;string&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CloudConnected&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;no&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;A_ARG_TYPE_String&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;string&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;no&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;A_ARG_TYPE_Uint&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;ui4&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;no&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;A_ARG_TYPE_Bool&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
  &amp;lt;/serviceStateTable&amp;gt;&lt;br /&gt;
&amp;lt;/scpd&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:PinsService</id>
		<title>Av:Developer:PinsService</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:PinsService"/>
				<updated>2018-08-17T09:10:11Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Created page with &amp;quot;= Overview =  A pin is a set of instructions to switch source or play one or more tracks on a device. Some pins will have wholly predictable results (e.g. switch to Analog2, play...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
A pin is a set of instructions to switch source or play one or more tracks on a device. Some pins will have wholly predictable results (e.g. switch to Analog2, play named playlist); others may be more dynamic (e.g. play the latest podcast from a given feed or a curated playlist of the week from a streaming service).&lt;br /&gt;
&lt;br /&gt;
The Pins service provides access both device-specific and account-wide pins. Both classes of pin can be read from or invoked on a device. Device-specific pins can also be edited; account-wide pins may be editable via a device but should also have edit APIs in the service or location that provides general account support.&lt;br /&gt;
&lt;br /&gt;
= State Variables =&lt;br /&gt;
== DeviceMax ==&lt;br /&gt;
The maximum number of device-specific pins supported&lt;br /&gt;
&lt;br /&gt;
== AccountMax ==&lt;br /&gt;
The maximum number of account-wide pins supported&lt;br /&gt;
&lt;br /&gt;
== Modes ==&lt;br /&gt;
JSON array of strings identifying the different styles of pins supported&lt;br /&gt;
&lt;br /&gt;
== CloudConnected ==&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if a connection is available to cloud-backed master copy of account pins (i.e. when account pins are editable); &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
== IdArray ==&lt;br /&gt;
JSON array of identifiers (unsigned integer) for all pins. &lt;br /&gt;
&amp;lt;br&amp;gt;Device pins are listed first, followed by Account pins. i.e. array will always have &amp;lt;tt&amp;gt;DeviceMax&amp;lt;/tt&amp;gt; + &amp;lt;tt&amp;gt;AccountMax&amp;lt;/tt&amp;gt; entries. &lt;br /&gt;
&amp;lt;br&amp;gt;Identifiers will normally be unique; &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; is a special case which signifies an empty pin.&lt;br /&gt;
&lt;br /&gt;
= Actions =&lt;br /&gt;
== GetDeviceMax ==&lt;br /&gt;
Read the &amp;lt;tt&amp;gt;DeviceMax&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
== GetAccountMax ==&lt;br /&gt;
Read the &amp;lt;tt&amp;gt;AccountMax&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
== GetModes ==&lt;br /&gt;
Read the &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
== GetCloudConnected ==&lt;br /&gt;
Read the &amp;lt;tt&amp;gt;CloudConnected&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
== GetIdArray ==&lt;br /&gt;
Read the &amp;lt;tt&amp;gt;IdArray&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
== ReadList ==&lt;br /&gt;
Input: JSON integer array, specifying ids of pins to be read. &lt;br /&gt;
&amp;lt;br&amp;gt;Output: JSON array of pins&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {unsigned integer, unique across device &amp;amp; account pins},&lt;br /&gt;
        &amp;quot;mode&amp;quot;: &amp;quot;where track(s) will be fetched from&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;instructs the device how to interpret the uri below&amp;quot;,&lt;br /&gt;
        &amp;quot;uri&amp;quot;: &amp;quot;absolute uri&amp;quot;,&lt;br /&gt;
        &amp;quot;title&amp;quot;: &amp;quot;Short text, may be user-visible&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Longer text, may be user-visible&amp;quot;,&lt;br /&gt;
        &amp;quot;artworkUri&amp;quot;: &amp;quot;absolute uri to image&amp;quot;,&lt;br /&gt;
        &amp;quot;shuffle&amp;quot;: {boolean}&lt;br /&gt;
    },&lt;br /&gt;
    { ... }&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== InvokeIndex ==&lt;br /&gt;
Invoke the pin at the specified index in &amp;lt;tt&amp;gt;IdArray&amp;lt;/tt&amp;gt;. This will stop anything that is currently playing and may clear any current playlist.&lt;br /&gt;
&lt;br /&gt;
== InvokeId ==&lt;br /&gt;
Invoke the pin with the specified id. This will stop anything that is currently playing and may clear any current playlist.&lt;br /&gt;
&lt;br /&gt;
== InvokeUri ==&lt;br /&gt;
Invoke a pin using data (mode, type, uri, shuffle) from a control point. Should be used by any control point that wants to determine which account to read pins from. (Note however that pins which themselves require cloud support to load cannot be loaded by the device - control points would have to load them directly into a playlist instead.) This will stop anything that is currently playing and may clear any current playlist.&lt;br /&gt;
&lt;br /&gt;
== SetDevice ==&lt;br /&gt;
Set a device pin, specifying the mode, type, uri, title, description, artworkUri and shuffle plus index into the set of device pins. &lt;br /&gt;
&amp;lt;br&amp;gt;Any pin currently assigned at the specified index will be replaced. &lt;br /&gt;
&amp;lt;br&amp;gt;Any playing content is unaffected (i.e. invoking then replacing a pin leaves the old representation of the pin playing). &lt;br /&gt;
index must be in the range &amp;lt;tt&amp;gt;[0..DeviceMax)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;Some errors are notified in response to this action. Success should only be assumed when an update is evented to IdArray showing a change in id at the specified index.&lt;br /&gt;
&lt;br /&gt;
== SetAccount ==&lt;br /&gt;
Set an account pin, specifying the mode, type, uri, title, description, artworkUri and shuffle plus index into the set of device pins. &lt;br /&gt;
&amp;lt;br&amp;gt;Any pin currently assigned at the specified index will be replaced. &lt;br /&gt;
&amp;lt;br&amp;gt;Any playing content is unaffected (i.e. invoking then replacing a pin leaves the old representation of the pin playing). &lt;br /&gt;
index must be in the range &amp;lt;tt&amp;gt;[0..AccountMax)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;Requests to update an account pin are proxied to a remote server so are likely to be slower and have greater chance of failure. &lt;br /&gt;
&amp;lt;br&amp;gt;Some errors are notified in response to this action. Success should only be assumed when an update is evented to &amp;lt;tt&amp;gt;IdArray&amp;lt;/tt&amp;gt; showing a change in id at &amp;lt;tt&amp;gt;DeviceMax + index&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Clear ==&lt;br /&gt;
Clear any content in the pin with the specified id. &lt;br /&gt;
&amp;lt;br&amp;gt;As with Set, changes to device pins are implemented locally; changes to account pins are proxied to a remote server. &lt;br /&gt;
&amp;lt;br&amp;gt;Some errors are notified in response to this action. Success should only be assumed when an update is evented to the sequence number for the specified id.&lt;br /&gt;
&lt;br /&gt;
== Swap ==&lt;br /&gt;
Swap contents of the 2 pins at the specified indices. &lt;br /&gt;
&amp;lt;br&amp;gt;Pins can only be swapped within either device or account lists.&lt;br /&gt;
&lt;br /&gt;
= Technical Details =&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
    Domain  : av.openhome.org&lt;br /&gt;
    Name    : Pins&lt;br /&gt;
    Version : 1&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Service Description (XML) ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;scpd xmlns=&amp;quot;urn:schemas-upnp-org:service-1-0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;specVersion&amp;gt;&lt;br /&gt;
    &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
    &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/specVersion&amp;gt;&lt;br /&gt;
  &amp;lt;actionList&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;GetDeviceMax&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;DeviceMax&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;DeviceMax&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;GetAccountMax&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;AccountMax&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;AccountMax&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;GetModes&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Modes&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;Modes&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;GetIdArray&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;IdArray&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;IdArray&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;GetCloudConnected&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CloudConnected&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CloudConnected&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;ReadList&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Ids&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;List&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;InvokeId&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Id&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;InvokeIndex&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Index&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;InvokeUri&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Mode&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Type&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Uri&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Bool&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SetDevice&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Index&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Mode&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Type&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Uri&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Title&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Description&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;ArtworkUri&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Bool&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SetAccount&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Index&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Mode&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Type&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Uri&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Title&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Description&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;ArtworkUri&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_String&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Bool&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Clear&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Id&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Swap&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Index1&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Index2&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_Uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
  &amp;lt;/actionList&amp;gt;&lt;br /&gt;
  &amp;lt;serviceStateTable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;DeviceMax&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;ui4&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;AccountMax&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;ui4&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Modes&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;string&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;IdArray&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;string&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CloudConnected&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;no&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;A_ARG_TYPE_String&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;string&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;no&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;A_ARG_TYPE_Uint&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;ui4&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;no&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;A_ARG_TYPE_Bool&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
  &amp;lt;/serviceStateTable&amp;gt;&lt;br /&gt;
&amp;lt;/scpd&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhMediaDevelopers</id>
		<title>OhMediaDevelopers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhMediaDevelopers"/>
				<updated>2018-08-17T08:56:38Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Add Pins&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Network Services =&lt;br /&gt;
ohMedia defines the following network services:&lt;br /&gt;
* [[Av:Developer:ProductService | Product]].  The core of a renderer and the only mandatory service.  The state of this service allows control points to infer which other services are present on a device.  In more complex installations it allows devices to mapped into a multi-room hi-fi system&lt;br /&gt;
* [[Av:Developer:PlaylistService | Playlist]].  An ordered list of tracks to be played.&lt;br /&gt;
* [[Av:Developer:RadioService | Radio]].  Browse and select from a list of favourite internet radio, podcast and listen again presets.&lt;br /&gt;
* [[Av:Developer:InfoService | Info]].  Report information about currently playing track.&lt;br /&gt;
* [[Av:Developer:TimeService | Time]].  Report information about progress through a track.&lt;br /&gt;
* [[Av:Developer:VolumeService | Volume]].  Control volume on a renderer or a connected pre-amp.&lt;br /&gt;
* [[Av:Developer:TransportService | Transport]].  Source-independent transport controls.&lt;br /&gt;
* [[Av:Developer:SenderService | Sender]].  Indicate presence and state of a Songcast sender.&lt;br /&gt;
* [[Av:Developer:ReceiverService | Receiver]].  Control a Songcast receiver.&lt;br /&gt;
* [[Av:Developer:CredentialsService | Credentials]].  Securely manage login details for external services supported by a device.&lt;br /&gt;
* [[Av:Developer:PinsService | Pins]].  Quick access to smart presets, supporting dynamic content.&lt;br /&gt;
* NetworkMonitor.  Measures network performance.&lt;br /&gt;
* [[Av:Developer:PlaylistManagerService | PlaylistManager]].  Included in media servers.  Allows playlists to be shared between renderers and saved for future reuse.&lt;br /&gt;
&lt;br /&gt;
The [[Av:Developer:EriskayServices | Eriskay]] family of services will later replace these.  Feedback on Eriskay is welcomed.&lt;br /&gt;
&lt;br /&gt;
= UPnP =&lt;br /&gt;
All ohMedia products publish and/or consume network services using UPnP.  This is enabled by [[OhNet | ohNet]] - a cross-platform UPnP stack suitable for use in control points and devices.  ohNet is open source, liberally licensed and intended for use in external products.&lt;br /&gt;
&lt;br /&gt;
= ODP =&lt;br /&gt;
[[Av:Developer:Odp | OpenHome Device Protocol]] (ODP) allows control of and evented updates from a device via a single socket.  [https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
All services that are available using over UPnP are also available using ODP.  The same auto-generated 'proxies' allow control point authors to invoke an action as a single function call and register callbacks to be informed of evented updates.&lt;br /&gt;
&lt;br /&gt;
= Songcast =&lt;br /&gt;
The Songcast brand encompasses a range of products and protocols.&lt;br /&gt;
&lt;br /&gt;
== Desktop senders ==&lt;br /&gt;
Virtual audio drivers that send all audio from a Windows or Mac device to a songcast receiver.  [https://www.linn.co.uk/software#songcast Linn] provide a full implementation of these.  The bulk of the code required is also available in the [https://github.com/openhome/ohSongcast ohSongcast] repo.&lt;br /&gt;
&lt;br /&gt;
== Multi-room ==&lt;br /&gt;
The Songcast protocol enables synchronised playing of audio from an unbounded number of ohMedia renderers.&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/openhome/ohSongcast ohSongcast] repo provides a cross-platform C++ library offering much of the code needed to write a stand-alone songcast sender.  The [https://github.com/openhome/ohPipeline ohPipeline] repo contains a reference sender and receiver fully integrated to the OpenHome reference audio pipeline.&lt;br /&gt;
&lt;br /&gt;
The Songcast protocols are also documented:&lt;br /&gt;
* [[Av:Developer:Songcast:Ohm | OHM/OHU protocol specification]]&lt;br /&gt;
* [[Av:Developer:Songcast:Ohz | OHZ protocol specification]]&lt;br /&gt;
&lt;br /&gt;
== Direct ==&lt;br /&gt;
A specialised protocol, offering simpler integration and potentially higher audio quality, used when there is a single receiver and the sender has control over the rate of streaming (this often means that the sender is responsible for audio decode).&lt;br /&gt;
&lt;br /&gt;
More information, including protocol spec and sample code is available [[Av:Developer:Scd | here]].&lt;br /&gt;
&lt;br /&gt;
= Topology =&lt;br /&gt;
ohMedia models a home as a number of hi-fi systems, which are located in rooms.&lt;br /&gt;
&lt;br /&gt;
A hi-fi system is modelled as a hierarchical tree of products, where a product is defined as a single physical box that is located in a room, has a unique name within the room, has at least one output and any number of inputs.&lt;br /&gt;
&lt;br /&gt;
A product is modelled through the [[Av:Developer:ProductService | Product]] service specification.&lt;br /&gt;
&lt;br /&gt;
When a control point wants to construct a model of a user's home they use the Topology algorithm:&lt;br /&gt;
* discover all the products in the home that have a Product service&lt;br /&gt;
* group the discovered products based on the room they are in&lt;br /&gt;
* create a hierarchical tree structure by matching source names to product names *&lt;br /&gt;
* discover source functionality based on source type&lt;br /&gt;
* discover additional functionality based on product attributes&lt;br /&gt;
Example implementations of the Topology algorithm are available in C# and C++ from the [https://github.com/openhome/ohTopology ohTopology] github repo.&lt;br /&gt;
&lt;br /&gt;
A more detailed description of the ohTopology software can be found [[Av:Developer:ohTopologyDescription | here]].&lt;br /&gt;
&lt;br /&gt;
= Streaming Services =&lt;br /&gt;
Both Linn's DS  and [[OhMediaPlayer | ohMediaPlayer]] include reference implementations for the following streaming services:&lt;br /&gt;
* [[TidalStreamingService | Tidal]]&lt;br /&gt;
* [[QobuzStreamingService | Qobuz]]&lt;br /&gt;
* [[CalmRadioInternetRadio | Calm Radio]]&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhNet</id>
		<title>OhNet</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhNet"/>
				<updated>2018-06-07T12:28:17Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Updated link to prebuilt binaries&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=ohNet=&lt;br /&gt;
&lt;br /&gt;
== What is it? ==&lt;br /&gt;
OpenHome Networking (ohNet) is a modern, cross platform UPnP stack.  ohNet includes both a control point and a device stack that can be used together or independently.  It runs on Linux, Windows, Mac, iOS and Android.  The public APIs are available for the device and control point stacks in C++, C#, Java and C.  JavaScript and Python APIs are also provided for the control point stack.&lt;br /&gt;
&lt;br /&gt;
UPnP services are presented as classes with actions appearing as functions and state variables appearing as member variables.  These classes are referred to as proxies for users of the control point stack and providers for users of the device stack.&lt;br /&gt;
&lt;br /&gt;
Proxies and Providers are included for all OpenHome and UPnP AV services.  If your application uses other services, ohNet includes a tool (ohNetGen) to generate proxies and/or providers from the service XML in any of the supported languages.&lt;br /&gt;
&lt;br /&gt;
Source code is available under a [https://opensource.org/licenses/MIT MIT license].&lt;br /&gt;
&lt;br /&gt;
== How do I get it? ==&lt;br /&gt;
ohNet is available as [https://github.com/openhome/ohNet source code].  Setup a (free) github account then&lt;br /&gt;
&lt;br /&gt;
  git clone git@github.com:openhome/ohNet.git ohnet&lt;br /&gt;
&lt;br /&gt;
build using&lt;br /&gt;
&lt;br /&gt;
  cd ohnet&lt;br /&gt;
  make&lt;br /&gt;
&lt;br /&gt;
There are also [https://s3-eu-west-1.amazonaws.com/linn-artifacts-public/index.html#artifacts/ohNet/ binaries available] for certain popular platforms/architectures.&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
=== Overview docs ===&lt;br /&gt;
* [http://builds.openhome.org/releases/ohNet_ControlPointStack.pdf Control Point stack (PDF)]&lt;br /&gt;
* [http://builds.openhome.org/releases/ohNet_DeviceStack.pdf Device stack (PDF)]&lt;br /&gt;
&lt;br /&gt;
=== API docs ===&lt;br /&gt;
* [http://www.openhome.org/build/nightly/docs/CppStd/ C++]&lt;br /&gt;
* [http://www.openhome.org/build/nightly/docs/Cs/ C#]&lt;br /&gt;
* [http://www.openhome.org/build/nightly/docs/Java/ Java]&lt;br /&gt;
* [http://www.openhome.org/build/nightly/docs/Js/ JavaScript]&lt;br /&gt;
* [http://www.openhome.org/build/nightly/docs/C/ C]&lt;br /&gt;
&lt;br /&gt;
=== Discussion ===&lt;br /&gt;
[http://forums.openhome.org/forumdisplay.php?fid=5 Developer forum]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ohNet is written using C++ with std::string replaced by special buffer classes.  These buffer classes allow for more efficient use of memory at the cost of a steeper learning curve. Memory use benefits can be especially pronounced for the Device stack.  [http://www.openhome.org/build/nightly/docs/CppCore/ API docs] for this version of the stack are available but the buffer classes are intended for internal use of the library and are as such currently undocumented.&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Scd</id>
		<title>Av:Developer:Scd</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Scd"/>
				<updated>2018-02-21T14:25:33Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: FormatDsd&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Songcast Direct =&lt;br /&gt;
== Overview ==&lt;br /&gt;
Songcast Direct (SCD) can be used to send decoded audio from any computing device to an OpenHome device.  The Sender device is responsible for decoding audio to PCM, framing this in a simple protocol and making it available via a simple TCP server.  The Receiver pulls data from this server, giving the Receiver complete control of the audio clock.&lt;br /&gt;
&lt;br /&gt;
A Songcast Direct sender performs a broadly similar role to a Songcast sender.  Applications that perform their own decoding to PCM will find SCD is easier to integrate and offers higher audio performance:&lt;br /&gt;
* There is a constant TCP connection between sender and receiver, avoiding the need for application-level resend support&lt;br /&gt;
* It uses the clock of the receiver, allowing for higher quality playback if the sender is on a desktop computer&lt;br /&gt;
* It offers the receiver limited control over the stream – initially seeking within a track or skipping between tracks.  While the primary control UI may reside on the sender device, this allows for integration with any Ir handset for the receiver.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd ohPipeline] contains sample code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;WavSender&amp;lt;/tt&amp;gt; contains an example of a trivial SCD Sender, scanning a single directory and decoding then sending any WAV files it finds. (Note that compilation of this is currently disabled.  &amp;lt;tt&amp;gt;DirScanner::Run()&amp;lt;/tt&amp;gt; contains code from an experimental precursor to C++17's &amp;lt;tt&amp;gt;std::filesystem::directory_iterator&amp;lt;/tt&amp;gt;.  Current code is compatible with VS2013; it should only require a couple of lines of change to make this compile against any more recent compiler.)&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd Scd] and [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd/Sender Sender] directories should be usable without any change.  It will be possible to write a commercial quality sender using the &amp;lt;tt&amp;gt;ScdSender&amp;lt;/tt&amp;gt; library, passing audio into &amp;lt;tt&amp;gt;IScdSupply&amp;lt;/tt&amp;gt; and relying on the configuration of &amp;lt;tt&amp;gt;ScdMsgFactory&amp;lt;/tt&amp;gt; to determine how much audio is buffered by the Sender.&lt;br /&gt;
&lt;br /&gt;
Sample code demonstrating how a Sender can control a Receiver via ODP is coming soon.  For now, see [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP tests] for a basic example.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
=== SSDP ===&lt;br /&gt;
First search for &amp;lt;tt&amp;gt;av-openhome-org:service:Product:2&amp;lt;/tt&amp;gt; then either&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Attributes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;Transport&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Transport&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;SourceXml&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; for a source with &amp;lt;tt&amp;gt;Type&amp;lt;/tt&amp;gt; of &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== mDNS ===&lt;br /&gt;
Search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; service to identify ODP endpoint&lt;br /&gt;
&lt;br /&gt;
== Control ==&lt;br /&gt;
Control of the Receiver is out of band, via the standard [[OhMediaDevelopers#Network_Services | OpenHome network APIs]].  These are available over UPnP or [[OhMediaDevelopers#ODP | ODP]] (a single connected socket).&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
The protocol used for communication between Sender and Receiver contains the following message types:&lt;br /&gt;
{|&lt;br /&gt;
! '''Type'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
! '''Sent by'''&lt;br /&gt;
|-&lt;br /&gt;
| Ready&lt;br /&gt;
| Signals availability and version support to other party&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataDidl &lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataOh&lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Format&lt;br /&gt;
| Format for the following (PCM) audio. Must be sent before any audio.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| FormatDsd&lt;br /&gt;
| Format for the following (DSD) audio. Must be sent before any audio.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Audio&lt;br /&gt;
| Decoded audio.  Can only be sent after a &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; message describing  its sample rate etc.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextDidl&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextOh&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].  Note that a uri does not need to be specified.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Halt&lt;br /&gt;
| Indicates that a break in audio follows.  E.g. at the end of a track with no further tracks to be played, or when the Sender has paused.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Disconnect&lt;br /&gt;
| Indicates that the originator of the message is closing its SCD session. No further audio will be available. The message receiver should disconnect its socket.&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| Seek&lt;br /&gt;
| Indicates that the Receiver wants to jump to a different point in the current track.&amp;lt;br&amp;gt;Is only sent for tracks that the Sender has indicated support seeking.&lt;br /&gt;
| Receiver&lt;br /&gt;
|-&lt;br /&gt;
| Skip&lt;br /&gt;
| Indicates that the Receiver wants to immediately jump to the next or previous track.&lt;br /&gt;
| Receiver&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A SCD session is initiated by the Sender.  It instantiates a simple TCP server then instructs the Receiver to start playing from it.&lt;br /&gt;
&lt;br /&gt;
The Receiver connects to the Sender and sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, indicating the protocol version it supports.  If the Sender is compatible with this version, it responds with a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the same version.  Otherwise, the Sender sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the version it supports.  If the Receiver cannot support this version, it must close the connection.&lt;br /&gt;
&lt;br /&gt;
After sending a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, the Sender should send either &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; (if it has nothing to send yet) or one of &amp;lt;tt&amp;gt;MetadataDidl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;MetadataOh&amp;lt;/tt&amp;gt; plus &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt;.  The order of &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; versus &amp;lt;tt&amp;gt;Metadata*&amp;lt;/tt&amp;gt; is not important.&lt;br /&gt;
&lt;br /&gt;
After this, the Sender should then send &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.  Any number of &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; messages can be sent until the end of the stream is reached.  &amp;lt;tt&amp;gt;Metatext&amp;lt;/tt&amp;gt; messages (either &amp;lt;tt&amp;gt;Didl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Oh&amp;lt;/tt&amp;gt;) may be interleaved with &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; message implies that a break in audio may follow.  If this break is during a stream, the Sender must have applied attenuation to samples immediately before this to avoid any audio artifacts at the break in transmission.  Senders which cannot do this should implement pausing of streams using the Transport.Pause control API instead.&lt;br /&gt;
&lt;br /&gt;
The details of the wire protocol are shown below.  Note that all multi-byte integer values are big endian.&lt;br /&gt;
{|&lt;br /&gt;
! '''Bytes'''&lt;br /&gt;
! '''Name'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| '''Header'''&lt;br /&gt;
|&lt;br /&gt;
| Prefixes to all messages below&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Signature&lt;br /&gt;
| 0x73, 0x63, 0x64,0x20 ('scd ')&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Type&lt;br /&gt;
| The type of message:&lt;br /&gt;
* 0 – Ready&lt;br /&gt;
* 1 – MetadataDidl&lt;br /&gt;
* 2 - MetaDataOh&lt;br /&gt;
* 3 – Format&lt;br /&gt;
* 4 – FormatDsd&lt;br /&gt;
* 5 – Audio&lt;br /&gt;
* 7 – MetatextDidl&lt;br /&gt;
* 8 – MetatextOh&lt;br /&gt;
* 9 – Halt&lt;br /&gt;
* 10 – Disconnect&lt;br /&gt;
* 11 – Seek&lt;br /&gt;
* 12 – Skip&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Length&lt;br /&gt;
| Length in bytes of the whole message including this header&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Reserved&lt;br /&gt;
| Unused, reserved for future use&lt;br /&gt;
|-&lt;br /&gt;
| '''Ready'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Major Version&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Minor Version&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| TrackUriLength&lt;br /&gt;
| Length, in bytes, of the track URI&lt;br /&gt;
|-&lt;br /&gt;
| m&lt;br /&gt;
| TrackUri&lt;br /&gt;
| The track URI, where m = TrackUriLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| MetadataLength&lt;br /&gt;
| Length, in bytes, of the track metadata, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metadata&lt;br /&gt;
| The track metadata, where n = MetadataLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metadata element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metadata element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metadata elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Format'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| BitDepth&lt;br /&gt;
| Bit depth of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| SampleRate&lt;br /&gt;
| Sample rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Channels&lt;br /&gt;
| Number of channels of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| BitRate&lt;br /&gt;
| Bit rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SampleStart&lt;br /&gt;
| Sample position of the first sample in the next &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; message&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SamplesTotal&lt;br /&gt;
| Total number of samples in the following audio (requirement for this to be confirmed)&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Flags&lt;br /&gt;
|&lt;br /&gt;
* Bit 0 - Seekable&lt;br /&gt;
* Bit 1 - Lossless&lt;br /&gt;
* Bit 2 - Live (content generated upstream of the Sender, e.g. internet radio)&lt;br /&gt;
* Bit 3 - Broadcastable (whether the Receiver is allowed to offer the following audio via any multi-room protocols&lt;br /&gt;
* Bits 4-7 - Reserved.  Must be zero.&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| CodecNameLength&lt;br /&gt;
| Length, in bytes, of the codec name&lt;br /&gt;
|-&lt;br /&gt;
| r&lt;br /&gt;
| CodecName&lt;br /&gt;
| The codec name, where r = CodecNameLength&lt;br /&gt;
|-&lt;br /&gt;
| '''FormatDsd'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| SampleRate&lt;br /&gt;
| Sample rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Channels&lt;br /&gt;
| Number of channels of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| SampleBlockBits&lt;br /&gt;
| Block size (in bits) of DSD data.  2 for stereo where left/right channels are interleaved, 16 for stereo with one byte of left subsamples followed by one byte of right subsamples, etc.&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SampleStart&lt;br /&gt;
| Sample position of the first sample in the next &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; message&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SamplesTotal&lt;br /&gt;
| Total number of samples in the following audio (requirement for this to be confirmed)&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Flags&lt;br /&gt;
|&lt;br /&gt;
* Bit 0 - Seekable&lt;br /&gt;
* Bit 1-2 - Reserved.  Must be zero.&lt;br /&gt;
* Bit 3 - Broadcastable (whether the Receiver is allowed to offer the following audio via any multi-room protocols&lt;br /&gt;
* Bits 4-7 - Reserved.  Must be zero.&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| CodecNameLength&lt;br /&gt;
| Length, in bytes, of the codec name&lt;br /&gt;
|-&lt;br /&gt;
| r&lt;br /&gt;
| CodecName&lt;br /&gt;
| The codec name, where r = CodecNameLength&lt;br /&gt;
|-&lt;br /&gt;
| '''Audio'''&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| NumSamples&lt;br /&gt;
| The number of audio samples in this message&lt;br /&gt;
|-&lt;br /&gt;
| s&lt;br /&gt;
| AudioData&lt;br /&gt;
| Audio data.  Where s = NumSamples * (BitDepth/8) * NumChannels.&amp;lt;br&amp;gt;Multi-channel audio must supply data sample at a time, with left channel first.  Audio is packed (i.e. no padding bytes rounding samples up to 32-bit boundaries) and big endian.&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Metatext Length&lt;br /&gt;
| Length, in bytes, of the metatext, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metatext&lt;br /&gt;
| The metatext, where n = MetatextLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metatext element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metatext element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metatext elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Halt'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Disconnect'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Seek'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|-&lt;br /&gt;
| '''Skip'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2018-01-15T13:30:10Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Eventing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
=== Framing ===&lt;br /&gt;
Each message, in either direction, is a JSON object followed by a newline (&amp;lt;tt&amp;gt;'\n'&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Announcement ===&lt;br /&gt;
When a client connects, a device announces its capabilities:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;:&amp;quot;announcement&amp;quot;,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;:2,&lt;br /&gt;
        &amp;quot;devices&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;:&amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service1&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service2&amp;quot;, &amp;quot;version&amp;quot;:2 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service3&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service4&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service5&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Control ===&lt;br /&gt;
The control point can invoke an action on a device as follows.  This will block until a response is sent.  Note that it is possible that the control point may receive other messages (e.g. &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt; - see below) before the action response.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each input argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;action&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 1 },&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;action_name&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
            ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;userAgent&amp;quot;:&amp;quot;optional client identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation is successful.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each output argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation fails:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Eventing ===&lt;br /&gt;
Subscribe to a particular service.  On successful completion, the device will send out unsolicited messages (with type &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt;) whenever one or more evented properties of a service change.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 },&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request succeeds.  The subscription id (sid) will be included in all later evented updates for this subscription.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request fails.  No later evented updates will be sent.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Unsubscribe (halt a particular stream of evented updates).&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when an unsubscribe completes.  No evented updates for this subscription will be sent after this.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A device will send the following whenever one or more evented properties change on a service with an active subscription.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each property will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for the associated &amp;lt;tt&amp;gt;stateVariable&amp;lt;/tt&amp;gt; in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;notify&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2018-01-15T13:29:01Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Control */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
=== Framing ===&lt;br /&gt;
Each message, in either direction, is a JSON object followed by a newline (&amp;lt;tt&amp;gt;'\n'&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Announcement ===&lt;br /&gt;
When a client connects, a device announces its capabilities:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;:&amp;quot;announcement&amp;quot;,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;:2,&lt;br /&gt;
        &amp;quot;devices&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;:&amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service1&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service2&amp;quot;, &amp;quot;version&amp;quot;:2 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service3&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service4&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service5&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Control ===&lt;br /&gt;
The control point can invoke an action on a device as follows.  This will block until a response is sent.  Note that it is possible that the control point may receive other messages (e.g. &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt; - see below) before the action response.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each input argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;action&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 1 },&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;action_name&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
            ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;optional request identifier&amp;quot;,&lt;br /&gt;
        &amp;quot;userAgent&amp;quot;:&amp;quot;optional client identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation is successful.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each output argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ],&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation fails:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: null,&lt;br /&gt;
        &amp;quot;correlationId&amp;quot;:&amp;quot;echoed from request&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Eventing ===&lt;br /&gt;
Subscribe to a particular service.  On successful completion, the device will send out unsolicited messages (with type &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt;) whenever one or more evented properties of a service change.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request succeeds.  The subscription id (sid) will be included in all later evented updates for this subscription.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request fails.  No later evented updates will be sent.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;sid&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Unsubscribe (halt a particular stream of evented updates).&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when an unsubscribe completes.  No evented updates for this subscription will be sent after this.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribeResponse&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A device will send the following whenever one or more evented properties change on a service with an active subscription.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each property will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for the associated &amp;lt;tt&amp;gt;stateVariable&amp;lt;/tt&amp;gt; in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;notify&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:TransportService</id>
		<title>Av:Developer:TransportService</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:TransportService"/>
				<updated>2018-01-10T11:46:05Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* SeekSecondAbsolute */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Transport Service =&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Transport service provides source-independent control of play, pause, stop, skip and seek.&lt;br /&gt;
&lt;br /&gt;
If a device's [[Av:Developer:ProductService | Product]] service reports an attribute &amp;lt;tt&amp;gt;&amp;quot;Transport&amp;quot;&amp;lt;/tt&amp;gt;, then that device is guaranteed to bear the Transport service.  If the Transport service is available, all its properties and actions must be fully implemented.&lt;br /&gt;
&lt;br /&gt;
== Evented Properties ==&lt;br /&gt;
=== Modes ===&lt;br /&gt;
List of available modes (JSON array of strings).&lt;br /&gt;
&lt;br /&gt;
=== CanSkipNext ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;SkipNext&amp;lt;/tt&amp;gt; action is currently available; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
Any mode that is sometimes capable of changing stream as a consequence of &amp;lt;tt&amp;gt;SkipNext&amp;lt;/tt&amp;gt; will always report &amp;lt;tt&amp;gt;CanSkipNext&amp;lt;/tt&amp;gt; as &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== CanSkipPrevious ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;SkipPrevious&amp;lt;/tt&amp;gt; action is currently available; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
Any mode that is sometimes capable of changing stream as a consequence of &amp;lt;tt&amp;gt;SkipPrevious&amp;lt;/tt&amp;gt; will always report &amp;lt;tt&amp;gt;CanSkipPrevious&amp;lt;/tt&amp;gt; as &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== CanRepeat ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;SetRepeat&amp;lt;/tt&amp;gt; action is currently available; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
=== CanShuffle ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;SetShuffle&amp;lt;/tt&amp;gt; action is currently available; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
=== StreamId ===&lt;br /&gt;
Integer id, uniquely identifying the current stream.&lt;br /&gt;
&lt;br /&gt;
=== CanSeek ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;SeekSecondAbsolute&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;SeekSecondRelative&amp;lt;/tt&amp;gt; actions are available for the current stream; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
=== CanPause ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the stream can be paused (so is not being played at a rate determined by a remote sender); &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
=== TransportState ===&lt;br /&gt;
One of&lt;br /&gt;
* &amp;lt;tt&amp;gt;Playing&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;Paused&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;Stopped&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;Buffering&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;Waiting&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Repeat ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if repeat mode is currently enabled; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Shuffle ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if shuffle mode is currently enabled; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Actions ==&lt;br /&gt;
=== PlayAs ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (in string mode, in string command)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Start a new stream playing, specifying both a mode (source) to be used and a mode-specific command which describes the track to be played. Common options for [[Av:Developer:TransportPlayAsCommands | modes and commands]] are documented separately.&lt;br /&gt;
&lt;br /&gt;
=== Play ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: None&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Start a pending stream playing.&lt;br /&gt;
&lt;br /&gt;
A stream must be ready to play. Possibly via calls to another network service.&lt;br /&gt;
&lt;br /&gt;
Behaviour when a stream is already playing varies depending on the active modes (source).&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: None&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Pause the current stream.&lt;br /&gt;
&lt;br /&gt;
Returns a &amp;lt;tt&amp;gt;801&amp;lt;/tt&amp;gt; fault code if the current channel does not support being paused (is being played at a rate determined by a remote sender).&lt;br /&gt;
&lt;br /&gt;
=== Stop ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: None&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
Stop the current stream.&lt;br /&gt;
&lt;br /&gt;
=== Next ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: None&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Move to the next stream (i.e. skip forwards).  Determination of what comes next may vary between sources/modes.  If &amp;lt;tt&amp;gt;TransportState&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;Stopped&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Paused&amp;lt;/tt&amp;gt;, try to start playing.&lt;br /&gt;
&lt;br /&gt;
=== Previous ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: None&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Move to the previous stream (i.e. skip backwards).  If &amp;lt;tt&amp;gt;TransportState&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;Stopped&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Paused&amp;lt;/tt&amp;gt;, try to start playing.&lt;br /&gt;
&lt;br /&gt;
Returns a &amp;lt;tt&amp;gt;801&amp;lt;/tt&amp;gt; fault code if the current channel does not support skipping backwards. &lt;br /&gt;
&lt;br /&gt;
=== SetRepeat ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (in uint repeat)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Sets the Repeat state of the device, affecting all sources that are capable of implementing a repeat feature.&lt;br /&gt;
&lt;br /&gt;
=== SetShuffle ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (in uint shuffle)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Sets the Shuffle state of the device, affecting all sources that are capable of implementing a randomise feature.&lt;br /&gt;
&lt;br /&gt;
=== SeekSecondAbsolute ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (in uint streamId, in uint secondsAbsolute)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Seek to an absolute position in the current stream.  If &amp;lt;tt&amp;gt;TransportState&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;Stopped&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Paused&amp;lt;/tt&amp;gt;, try to start playing.&lt;br /&gt;
&lt;br /&gt;
Returns a &amp;lt;tt&amp;gt;803&amp;lt;/tt&amp;gt; fault code if the seek is not possible.&lt;br /&gt;
&lt;br /&gt;
=== SeekSecondRelative ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (in uint streamId, in int secondsRelative)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Seek to a position relative to what's currently playing in the current stream.  If &amp;lt;tt&amp;gt;TransportState&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;Stopped&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Paused&amp;lt;/tt&amp;gt;, try to start playing.&lt;br /&gt;
&lt;br /&gt;
Returns a &amp;lt;tt&amp;gt;803&amp;lt;/tt&amp;gt; fault code if the seek is not possible.&lt;br /&gt;
&lt;br /&gt;
=== TransportState ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (out string state)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Read the current value of the TransportState property.&lt;br /&gt;
&lt;br /&gt;
=== Modes ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (out string modes)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Return the value of the &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
=== ModeInfo ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (out string mode, out bool canSkipNext, out bool canSkipPrevious, out bool canRepeat, out bool canShuffle)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Reports the values of the &amp;lt;tt&amp;gt;Mode&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;CanSkipNext&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;CanSkipPrev&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;CanRepeat&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;CanShuffle&amp;lt;/tt&amp;gt; properties.&lt;br /&gt;
&lt;br /&gt;
=== StreamInfo ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: &amp;lt;br&amp;gt;&lt;br /&gt;
(out uint streamId, out bool seekable, out bool pausable)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reports current stream information:&lt;br /&gt;
* &amp;lt;tt&amp;gt;StreamId&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;Seekable&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;Pausable&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== StreamId ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (out uint streamId)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Read the current value of the &amp;lt;tt&amp;gt;StreamId&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
=== Repeat ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (out uint repeat)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Read the current value of the &amp;lt;tt&amp;gt;Repeat&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
=== Shuffle ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (out uint shuffle)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Read the current value of the &amp;lt;tt&amp;gt;Shuffle&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
== UPnP Service Description ==&lt;br /&gt;
For devices supporting the UPnP protocol, the service description is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;name: &amp;quot;Transport&amp;quot;&lt;br /&gt;
&amp;lt;br&amp;gt;domain: &amp;quot;av.openhome.org&amp;quot;&lt;br /&gt;
&amp;lt;br&amp;gt;version: &amp;quot;1&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;scpd xmlns=&amp;quot;urn:schemas-upnp-org:service-1-0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;specVersion&amp;gt;&lt;br /&gt;
    &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
    &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/specVersion&amp;gt;&lt;br /&gt;
  &amp;lt;actionList&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;PlayAs&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Mode&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_string&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Command&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_string&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Play&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Pause&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Stop&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SkipNext&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SkipPrevious&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SetRepeat&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Repeat&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;Repeat&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SetShuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;Shuffle&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SeekSecondAbsolute&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;StreamId&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;StreamId&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;SecondAbsolute&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SeekSecondRelative&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;StreamId&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;StreamId&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;SecondRelative&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_int&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;TransportState&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;State&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;TransportState&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Modes&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Modes&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;Modes&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;ModeInfo&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CanSkipNext&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CanSkipNext&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CanSkipPrevious&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CanSkipPrevious&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CanRepeat&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CanRepeat&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CanShuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CanShuffle&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;StreamInfo&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;StreamId&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;StreamId&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CanSeek&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CanSeek&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CanPause&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CanPause&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;StreamId&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;StreamId&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;StreamId&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Repeat&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Repeat&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;Repeat&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;Shuffle&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
  &amp;lt;/actionList&amp;gt;&lt;br /&gt;
  &amp;lt;serviceStateTable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Modes&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;string&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CanSkipNext&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CanSkipPrevious&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CanRepeat&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CanShuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;StreamId&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;ui4&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CanSeek&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CanPause&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;TransportState&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;string&amp;lt;/dataType&amp;gt;&lt;br /&gt;
      &amp;lt;allowedValueList&amp;gt;&lt;br /&gt;
        &amp;lt;allowedValue&amp;gt;Playing&amp;lt;/allowedValue&amp;gt;&lt;br /&gt;
        &amp;lt;allowedValue&amp;gt;Paused&amp;lt;/allowedValue&amp;gt;&lt;br /&gt;
        &amp;lt;allowedValue&amp;gt;Stopped&amp;lt;/allowedValue&amp;gt;&lt;br /&gt;
        &amp;lt;allowedValue&amp;gt;Buffering&amp;lt;/allowedValue&amp;gt;&lt;br /&gt;
        &amp;lt;allowedValue&amp;gt;Waiting&amp;lt;/allowedValue&amp;gt;&lt;br /&gt;
      &amp;lt;/allowedValueList&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Repeat&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;no&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;A_ARG_TYPE_uint&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;ui4&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;no&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;A_ARG_TYPE_int&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;i4&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;no&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;A_ARG_TYPE_string&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;string&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
  &amp;lt;/serviceStateTable&amp;gt;&lt;br /&gt;
&amp;lt;/scpd&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:TransportService</id>
		<title>Av:Developer:TransportService</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:TransportService"/>
				<updated>2018-01-10T11:45:51Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* SeekSecondRelative */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Transport Service =&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Transport service provides source-independent control of play, pause, stop, skip and seek.&lt;br /&gt;
&lt;br /&gt;
If a device's [[Av:Developer:ProductService | Product]] service reports an attribute &amp;lt;tt&amp;gt;&amp;quot;Transport&amp;quot;&amp;lt;/tt&amp;gt;, then that device is guaranteed to bear the Transport service.  If the Transport service is available, all its properties and actions must be fully implemented.&lt;br /&gt;
&lt;br /&gt;
== Evented Properties ==&lt;br /&gt;
=== Modes ===&lt;br /&gt;
List of available modes (JSON array of strings).&lt;br /&gt;
&lt;br /&gt;
=== CanSkipNext ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;SkipNext&amp;lt;/tt&amp;gt; action is currently available; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
Any mode that is sometimes capable of changing stream as a consequence of &amp;lt;tt&amp;gt;SkipNext&amp;lt;/tt&amp;gt; will always report &amp;lt;tt&amp;gt;CanSkipNext&amp;lt;/tt&amp;gt; as &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== CanSkipPrevious ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;SkipPrevious&amp;lt;/tt&amp;gt; action is currently available; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
Any mode that is sometimes capable of changing stream as a consequence of &amp;lt;tt&amp;gt;SkipPrevious&amp;lt;/tt&amp;gt; will always report &amp;lt;tt&amp;gt;CanSkipPrevious&amp;lt;/tt&amp;gt; as &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== CanRepeat ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;SetRepeat&amp;lt;/tt&amp;gt; action is currently available; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
=== CanShuffle ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;SetShuffle&amp;lt;/tt&amp;gt; action is currently available; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
=== StreamId ===&lt;br /&gt;
Integer id, uniquely identifying the current stream.&lt;br /&gt;
&lt;br /&gt;
=== CanSeek ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;SeekSecondAbsolute&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;SeekSecondRelative&amp;lt;/tt&amp;gt; actions are available for the current stream; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
=== CanPause ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if the stream can be paused (so is not being played at a rate determined by a remote sender); &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
=== TransportState ===&lt;br /&gt;
One of&lt;br /&gt;
* &amp;lt;tt&amp;gt;Playing&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;Paused&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;Stopped&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;Buffering&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;Waiting&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Repeat ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if repeat mode is currently enabled; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
=== Shuffle ===&lt;br /&gt;
&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if shuffle mode is currently enabled; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Actions ==&lt;br /&gt;
=== PlayAs ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (in string mode, in string command)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Start a new stream playing, specifying both a mode (source) to be used and a mode-specific command which describes the track to be played. Common options for [[Av:Developer:TransportPlayAsCommands | modes and commands]] are documented separately.&lt;br /&gt;
&lt;br /&gt;
=== Play ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: None&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Start a pending stream playing.&lt;br /&gt;
&lt;br /&gt;
A stream must be ready to play. Possibly via calls to another network service.&lt;br /&gt;
&lt;br /&gt;
Behaviour when a stream is already playing varies depending on the active modes (source).&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: None&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Pause the current stream.&lt;br /&gt;
&lt;br /&gt;
Returns a &amp;lt;tt&amp;gt;801&amp;lt;/tt&amp;gt; fault code if the current channel does not support being paused (is being played at a rate determined by a remote sender).&lt;br /&gt;
&lt;br /&gt;
=== Stop ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: None&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
Stop the current stream.&lt;br /&gt;
&lt;br /&gt;
=== Next ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: None&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Move to the next stream (i.e. skip forwards).  Determination of what comes next may vary between sources/modes.  If &amp;lt;tt&amp;gt;TransportState&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;Stopped&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Paused&amp;lt;/tt&amp;gt;, try to start playing.&lt;br /&gt;
&lt;br /&gt;
=== Previous ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: None&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Move to the previous stream (i.e. skip backwards).  If &amp;lt;tt&amp;gt;TransportState&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;Stopped&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Paused&amp;lt;/tt&amp;gt;, try to start playing.&lt;br /&gt;
&lt;br /&gt;
Returns a &amp;lt;tt&amp;gt;801&amp;lt;/tt&amp;gt; fault code if the current channel does not support skipping backwards. &lt;br /&gt;
&lt;br /&gt;
=== SetRepeat ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (in uint repeat)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Sets the Repeat state of the device, affecting all sources that are capable of implementing a repeat feature.&lt;br /&gt;
&lt;br /&gt;
=== SetShuffle ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (in uint shuffle)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Sets the Shuffle state of the device, affecting all sources that are capable of implementing a randomise feature.&lt;br /&gt;
&lt;br /&gt;
=== SeekSecondAbsolute ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (in uint streamId, in uint secondsAbsolute)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Seek to an absolute position in the current stream.  If &amp;lt;tt&amp;gt;TransportState&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;Stopped&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Paused&amp;lt;/tt&amp;gt;, try to start playing.&lt;br /&gt;
&lt;br /&gt;
Returns a &amp;lt;tt&amp;gt;801&amp;lt;/tt&amp;gt; fault code if the current stream does not support seek. &lt;br /&gt;
&amp;lt;br&amp;gt;Returns a &amp;lt;tt&amp;gt;803&amp;lt;/tt&amp;gt; fault code if the seek position is beyond the end of the stream.&lt;br /&gt;
&lt;br /&gt;
=== SeekSecondRelative ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (in uint streamId, in int secondsRelative)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Seek to a position relative to what's currently playing in the current stream.  If &amp;lt;tt&amp;gt;TransportState&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;Stopped&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Paused&amp;lt;/tt&amp;gt;, try to start playing.&lt;br /&gt;
&lt;br /&gt;
Returns a &amp;lt;tt&amp;gt;803&amp;lt;/tt&amp;gt; fault code if the seek is not possible.&lt;br /&gt;
&lt;br /&gt;
=== TransportState ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (out string state)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Read the current value of the TransportState property.&lt;br /&gt;
&lt;br /&gt;
=== Modes ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (out string modes)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Return the value of the &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
=== ModeInfo ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (out string mode, out bool canSkipNext, out bool canSkipPrevious, out bool canRepeat, out bool canShuffle)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Reports the values of the &amp;lt;tt&amp;gt;Mode&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;CanSkipNext&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;CanSkipPrev&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;CanRepeat&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;CanShuffle&amp;lt;/tt&amp;gt; properties.&lt;br /&gt;
&lt;br /&gt;
=== StreamInfo ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: &amp;lt;br&amp;gt;&lt;br /&gt;
(out uint streamId, out bool seekable, out bool pausable)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reports current stream information:&lt;br /&gt;
* &amp;lt;tt&amp;gt;StreamId&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;Seekable&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;Pausable&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== StreamId ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (out uint streamId)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Read the current value of the &amp;lt;tt&amp;gt;StreamId&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
=== Repeat ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (out uint repeat)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Read the current value of the &amp;lt;tt&amp;gt;Repeat&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
=== Shuffle ===&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Arguments: (out uint shuffle)&lt;br /&gt;
&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Read the current value of the &amp;lt;tt&amp;gt;Shuffle&amp;lt;/tt&amp;gt; property.&lt;br /&gt;
&lt;br /&gt;
== UPnP Service Description ==&lt;br /&gt;
For devices supporting the UPnP protocol, the service description is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;name: &amp;quot;Transport&amp;quot;&lt;br /&gt;
&amp;lt;br&amp;gt;domain: &amp;quot;av.openhome.org&amp;quot;&lt;br /&gt;
&amp;lt;br&amp;gt;version: &amp;quot;1&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;scpd xmlns=&amp;quot;urn:schemas-upnp-org:service-1-0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;specVersion&amp;gt;&lt;br /&gt;
    &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
    &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/specVersion&amp;gt;&lt;br /&gt;
  &amp;lt;actionList&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;PlayAs&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Mode&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_string&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Command&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_string&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Play&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Pause&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Stop&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SkipNext&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SkipPrevious&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SetRepeat&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Repeat&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;Repeat&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SetShuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;Shuffle&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SeekSecondAbsolute&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;StreamId&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;StreamId&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;SecondAbsolute&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_uint&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SeekSecondRelative&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;StreamId&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;StreamId&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;SecondRelative&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;in&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;A_ARG_TYPE_int&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;TransportState&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;State&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;TransportState&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Modes&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Modes&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;Modes&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;ModeInfo&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CanSkipNext&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CanSkipNext&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CanSkipPrevious&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CanSkipPrevious&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CanRepeat&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CanRepeat&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CanShuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CanShuffle&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;StreamInfo&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;StreamId&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;StreamId&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CanSeek&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CanSeek&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;CanPause&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;CanPause&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;StreamId&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;StreamId&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;StreamId&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Repeat&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Repeat&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;Repeat&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;argumentList&amp;gt;&lt;br /&gt;
        &amp;lt;argument&amp;gt;&lt;br /&gt;
          &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
          &amp;lt;direction&amp;gt;out&amp;lt;/direction&amp;gt;&lt;br /&gt;
          &amp;lt;relatedStateVariable&amp;gt;Shuffle&amp;lt;/relatedStateVariable&amp;gt;&lt;br /&gt;
        &amp;lt;/argument&amp;gt;&lt;br /&gt;
      &amp;lt;/argumentList&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
  &amp;lt;/actionList&amp;gt;&lt;br /&gt;
  &amp;lt;serviceStateTable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Modes&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;string&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CanSkipNext&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CanSkipPrevious&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CanRepeat&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CanShuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;StreamId&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;ui4&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CanSeek&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;CanPause&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;TransportState&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;string&amp;lt;/dataType&amp;gt;&lt;br /&gt;
      &amp;lt;allowedValueList&amp;gt;&lt;br /&gt;
        &amp;lt;allowedValue&amp;gt;Playing&amp;lt;/allowedValue&amp;gt;&lt;br /&gt;
        &amp;lt;allowedValue&amp;gt;Paused&amp;lt;/allowedValue&amp;gt;&lt;br /&gt;
        &amp;lt;allowedValue&amp;gt;Stopped&amp;lt;/allowedValue&amp;gt;&lt;br /&gt;
        &amp;lt;allowedValue&amp;gt;Buffering&amp;lt;/allowedValue&amp;gt;&lt;br /&gt;
        &amp;lt;allowedValue&amp;gt;Waiting&amp;lt;/allowedValue&amp;gt;&lt;br /&gt;
      &amp;lt;/allowedValueList&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Repeat&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;yes&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;Shuffle&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;no&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;A_ARG_TYPE_uint&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;ui4&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;no&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;A_ARG_TYPE_int&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;i4&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
    &amp;lt;stateVariable sendEvents=&amp;quot;no&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;A_ARG_TYPE_string&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;dataType&amp;gt;string&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;/stateVariable&amp;gt;&lt;br /&gt;
  &amp;lt;/serviceStateTable&amp;gt;&lt;br /&gt;
&amp;lt;/scpd&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Scd</id>
		<title>Av:Developer:Scd</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Scd"/>
				<updated>2018-01-04T09:27:14Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Protocol */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Songcast Direct =&lt;br /&gt;
== Overview ==&lt;br /&gt;
Songcast Direct (SCD) can be used to send decoded audio from any computing device to an OpenHome device.  The Sender device is responsible for decoding audio to PCM, framing this in a simple protocol and making it available via a simple TCP server.  The Receiver pulls data from this server, giving the Receiver complete control of the audio clock.&lt;br /&gt;
&lt;br /&gt;
A Songcast Direct sender performs a broadly similar role to a Songcast sender.  Applications that perform their own decoding to PCM will find SCD is easier to integrate and offers higher audio performance:&lt;br /&gt;
* There is a constant TCP connection between sender and receiver, avoiding the need for application-level resend support&lt;br /&gt;
* It uses the clock of the receiver, allowing for higher quality playback if the sender is on a desktop computer&lt;br /&gt;
* It offers the receiver limited control over the stream – initially seeking within a track or skipping between tracks.  While the primary control UI may reside on the sender device, this allows for integration with any Ir handset for the receiver.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd ohPipeline] contains sample code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;WavSender&amp;lt;/tt&amp;gt; contains an example of a trivial SCD Sender, scanning a single directory and decoding then sending any WAV files it finds. (Note that compilation of this is currently disabled.  &amp;lt;tt&amp;gt;DirScanner::Run()&amp;lt;/tt&amp;gt; contains code from an experimental precursor to C++17's &amp;lt;tt&amp;gt;std::filesystem::directory_iterator&amp;lt;/tt&amp;gt;.  Current code is compatible with VS2013; it should only require a couple of lines of change to make this compile against any more recent compiler.)&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd Scd] and [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd/Sender Sender] directories should be usable without any change.  It will be possible to write a commercial quality sender using the &amp;lt;tt&amp;gt;ScdSender&amp;lt;/tt&amp;gt; library, passing audio into &amp;lt;tt&amp;gt;IScdSupply&amp;lt;/tt&amp;gt; and relying on the configuration of &amp;lt;tt&amp;gt;ScdMsgFactory&amp;lt;/tt&amp;gt; to determine how much audio is buffered by the Sender.&lt;br /&gt;
&lt;br /&gt;
Sample code demonstrating how a Sender can control a Receiver via ODP is coming soon.  For now, see [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP tests] for a basic example.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
=== SSDP ===&lt;br /&gt;
First search for &amp;lt;tt&amp;gt;av-openhome-org:service:Product:2&amp;lt;/tt&amp;gt; then either&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Attributes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;Transport&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Transport&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;SourceXml&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; for a source with &amp;lt;tt&amp;gt;Type&amp;lt;/tt&amp;gt; of &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== mDNS ===&lt;br /&gt;
Search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; service to identify ODP endpoint&lt;br /&gt;
&lt;br /&gt;
== Control ==&lt;br /&gt;
Control of the Receiver is out of band, via the standard [[OhMediaDevelopers#Network_Services | OpenHome network APIs]].  These are available over UPnP or [[OhMediaDevelopers#ODP | ODP]] (a single connected socket).&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
The protocol used for communication between Sender and Receiver contains the following message types:&lt;br /&gt;
{|&lt;br /&gt;
! '''Type'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
! '''Sent by'''&lt;br /&gt;
|-&lt;br /&gt;
| Ready&lt;br /&gt;
| Signals availability and version support to other party&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataDidl &lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataOh&lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Format&lt;br /&gt;
| Format for the following audio. Must be sent before any audio.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Audio&lt;br /&gt;
| Decoded audio.  Can only be sent after a &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; message describing  its sample rate etc.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextDidl&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextOh&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].  Note that a uri does not need to be specified.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Halt&lt;br /&gt;
| Indicates that a break in audio follows.  E.g. at the end of a track with no further tracks to be played, or when the Sender has paused.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Disconnect&lt;br /&gt;
| Indicates that the originator of the message is closing its SCD session. No further audio will be available. The message receiver should disconnect its socket.&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| Seek&lt;br /&gt;
| Indicates that the Receiver wants to jump to a different point in the current track.&amp;lt;br&amp;gt;Is only sent for tracks that the Sender has indicated support seeking.&lt;br /&gt;
| Receiver&lt;br /&gt;
|-&lt;br /&gt;
| Skip&lt;br /&gt;
| Indicates that the Receiver wants to immediately jump to the next or previous track.&lt;br /&gt;
| Receiver&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A SCD session is initiated by the Sender.  It instantiates a simple TCP server then instructs the Receiver to start playing from it.&lt;br /&gt;
&lt;br /&gt;
The Receiver connects to the Sender and sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, indicating the protocol version it supports.  If the Sender is compatible with this version, it responds with a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the same version.  Otherwise, the Sender sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the version it supports.  If the Receiver cannot support this version, it must close the connection.&lt;br /&gt;
&lt;br /&gt;
After sending a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, the Sender should send either &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; (if it has nothing to send yet) or one of &amp;lt;tt&amp;gt;MetadataDidl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;MetadataOh&amp;lt;/tt&amp;gt; plus &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt;.  The order of &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; versus &amp;lt;tt&amp;gt;Metadata*&amp;lt;/tt&amp;gt; is not important.&lt;br /&gt;
&lt;br /&gt;
After this, the Sender should then send &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.  Any number of &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; messages can be sent until the end of the stream is reached.  &amp;lt;tt&amp;gt;Metatext&amp;lt;/tt&amp;gt; messages (either &amp;lt;tt&amp;gt;Didl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Oh&amp;lt;/tt&amp;gt;) may be interleaved with &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; message implies that a break in audio may follow.  If this break is during a stream, the Sender must have applied attenuation to samples immediately before this to avoid any audio artifacts at the break in transmission.  Senders which cannot do this should implement pausing of streams using the Transport.Pause control API instead.&lt;br /&gt;
&lt;br /&gt;
The details of the wire protocol are shown below.  Note that all multi-byte integer values are big endian.&lt;br /&gt;
{|&lt;br /&gt;
! '''Bytes'''&lt;br /&gt;
! '''Name'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| '''Header'''&lt;br /&gt;
|&lt;br /&gt;
| Prefixes to all messages below&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Signature&lt;br /&gt;
| 0x73, 0x63, 0x64,0x20 ('scd ')&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Type&lt;br /&gt;
| The type of message:&lt;br /&gt;
* 0 – Ready&lt;br /&gt;
* 1 – MetadataDidl&lt;br /&gt;
* 2 - MetaDataOh&lt;br /&gt;
* 3 – Format&lt;br /&gt;
* 5 – Audio&lt;br /&gt;
* 7 – MetatextDidl&lt;br /&gt;
* 8 – MetatextOh&lt;br /&gt;
* 9 – Halt&lt;br /&gt;
* 10 – Disconnect&lt;br /&gt;
* 11 – Seek&lt;br /&gt;
* 12 – Skip&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Length&lt;br /&gt;
| Length in bytes of the whole message including this header&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Reserved&lt;br /&gt;
| Unused, reserved for future use&lt;br /&gt;
|-&lt;br /&gt;
| '''Ready'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Major Version&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Minor Version&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| TrackUriLength&lt;br /&gt;
| Length, in bytes, of the track URI&lt;br /&gt;
|-&lt;br /&gt;
| m&lt;br /&gt;
| TrackUri&lt;br /&gt;
| The track URI, where m = TrackUriLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| MetadataLength&lt;br /&gt;
| Length, in bytes, of the track metadata, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metadata&lt;br /&gt;
| The track metadata, where n = MetadataLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metadata element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metadata element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metadata elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Format'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| BitDepth&lt;br /&gt;
| Bit depth of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| SampleRate&lt;br /&gt;
| Sample rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Channels&lt;br /&gt;
| Number of channels of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| BitRate&lt;br /&gt;
| Bit rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SampleStart&lt;br /&gt;
| Sample position of the first sample in the next &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; message&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SamplesTotal&lt;br /&gt;
| Total number of samples in the following audio (requirement for this to be confirmed)&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Flags&lt;br /&gt;
|&lt;br /&gt;
* Bit 0 - Seekable&lt;br /&gt;
* Bit 1 - Lossless&lt;br /&gt;
* Bit 2 - Live (content generated upstream of the Sender, e.g. internet radio)&lt;br /&gt;
* Bit 3 - Broadcastable (whether the Receiver is allowed to offer the following audio via any multi-room protocols&lt;br /&gt;
* Bits 4-7 - Reserved.  Must be zero.&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| CodecNameLength&lt;br /&gt;
| Length, in bytes, of the codec name&lt;br /&gt;
|-&lt;br /&gt;
| r&lt;br /&gt;
| CodecName&lt;br /&gt;
| The codec name, where r = CodecNameLength&lt;br /&gt;
|-&lt;br /&gt;
| '''Audio'''&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| NumSamples&lt;br /&gt;
| The number of audio samples in this message&lt;br /&gt;
|-&lt;br /&gt;
| s&lt;br /&gt;
| AudioData&lt;br /&gt;
| Audio data.  Where s = NumSamples * (BitDepth/8) * NumChannels.&amp;lt;br&amp;gt;Multi-channel audio must supply data sample at a time, with left channel first.  Audio is packed (i.e. no padding bytes rounding samples up to 32-bit boundaries) and big endian.&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Metatext Length&lt;br /&gt;
| Length, in bytes, of the metatext, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metatext&lt;br /&gt;
| The metatext, where n = MetatextLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metatext element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metatext element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metatext elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Halt'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Disconnect'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Seek'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|-&lt;br /&gt;
| '''Skip'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Scd</id>
		<title>Av:Developer:Scd</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Scd"/>
				<updated>2017-12-22T10:51:56Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Protocol */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Songcast Direct =&lt;br /&gt;
== Overview ==&lt;br /&gt;
Songcast Direct (SCD) can be used to send decoded audio from any computing device to an OpenHome device.  The Sender device is responsible for decoding audio to PCM, framing this in a simple protocol and making it available via a simple TCP server.  The Receiver pulls data from this server, giving the Receiver complete control of the audio clock.&lt;br /&gt;
&lt;br /&gt;
A Songcast Direct sender performs a broadly similar role to a Songcast sender.  Applications that perform their own decoding to PCM will find SCD is easier to integrate and offers higher audio performance:&lt;br /&gt;
* There is a constant TCP connection between sender and receiver, avoiding the need for application-level resend support&lt;br /&gt;
* It uses the clock of the receiver, allowing for higher quality playback if the sender is on a desktop computer&lt;br /&gt;
* It offers the receiver limited control over the stream – initially seeking within a track or skipping between tracks.  While the primary control UI may reside on the sender device, this allows for integration with any Ir handset for the receiver.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd ohPipeline] contains sample code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;WavSender&amp;lt;/tt&amp;gt; contains an example of a trivial SCD Sender, scanning a single directory and decoding then sending any WAV files it finds. (Note that compilation of this is currently disabled.  &amp;lt;tt&amp;gt;DirScanner::Run()&amp;lt;/tt&amp;gt; contains code from an experimental precursor to C++17's &amp;lt;tt&amp;gt;std::filesystem::directory_iterator&amp;lt;/tt&amp;gt;.  Current code is compatible with VS2013; it should only require a couple of lines of change to make this compile against any more recent compiler.)&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd Scd] and [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd/Sender Sender] directories should be usable without any change.  It will be possible to write a commercial quality sender using the &amp;lt;tt&amp;gt;ScdSender&amp;lt;/tt&amp;gt; library, passing audio into &amp;lt;tt&amp;gt;IScdSupply&amp;lt;/tt&amp;gt; and relying on the configuration of &amp;lt;tt&amp;gt;ScdMsgFactory&amp;lt;/tt&amp;gt; to determine how much audio is buffered by the Sender.&lt;br /&gt;
&lt;br /&gt;
Sample code demonstrating how a Sender can control a Receiver via ODP is coming soon.  For now, see [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP tests] for a basic example.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
=== SSDP ===&lt;br /&gt;
First search for &amp;lt;tt&amp;gt;av-openhome-org:service:Product:2&amp;lt;/tt&amp;gt; then either&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Attributes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;Transport&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Transport&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;SourceXml&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; for a source with &amp;lt;tt&amp;gt;Type&amp;lt;/tt&amp;gt; of &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== mDNS ===&lt;br /&gt;
Search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; service to identify ODP endpoint&lt;br /&gt;
&lt;br /&gt;
== Control ==&lt;br /&gt;
Control of the Receiver is out of band, via the standard [[OhMediaDevelopers#Network_Services | OpenHome network APIs]].  These are available over UPnP or [[OhMediaDevelopers#ODP | ODP]] (a single connected socket).&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
The protocol used for communication between Sender and Receiver contains the following message types:&lt;br /&gt;
{|&lt;br /&gt;
! '''Type'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
! '''Sent by'''&lt;br /&gt;
|-&lt;br /&gt;
| Ready&lt;br /&gt;
| Signals availability and version support to other party&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataDidl &lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataOh&lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Format&lt;br /&gt;
| Format for the following audio. Must be sent before any audio.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Audio&lt;br /&gt;
| Decoded audio.  Can only be sent after a &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; message describing  its sample rate etc.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextDidl&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextOh&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].  Note that a uri does not need to be specified.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Halt&lt;br /&gt;
| Indicates that a break in audio follows.  E.g. at the end of a track with no further tracks to be played, or when the Sender has paused.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Disconnect&lt;br /&gt;
| Indicates that the originator of the message is closing its SCD session. No further audio will be available. The message receiver should disconnect its socket.&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| Seek&lt;br /&gt;
| Indicates that the Receiver wants to jump to a different point in the current track.&amp;lt;br&amp;gt;Is only sent for tracks that the Sender has indicated support seeking.&lt;br /&gt;
| Receiver&lt;br /&gt;
|-&lt;br /&gt;
| Skip&lt;br /&gt;
| Indicates that the Receiver wants to immediately jump to the next or previous track.&lt;br /&gt;
| Receiver&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A SCD session is initiated by the Sender.  It instantiates a simple TCP server then instructs the Receiver to start playing from it.&lt;br /&gt;
&lt;br /&gt;
The Receiver connects to the Sender and sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, indicating the protocol version it supports.  If the Sender is compatible with this version, it responds with a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the same version.  Otherwise, the Sender sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the version it supports.  If the Receiver cannot support this version, it must close the connection.&lt;br /&gt;
&lt;br /&gt;
After sending a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, the Sender should send either &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; (if it has nothing to send yet) or one of &amp;lt;tt&amp;gt;MetadataDidl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;MetadataOh&amp;lt;/tt&amp;gt; plus &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt;.  The order of &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; versus &amp;lt;tt&amp;gt;Metadata*&amp;lt;/tt&amp;gt; is not important.&lt;br /&gt;
&lt;br /&gt;
After this, the Sender should then send &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.  Any number of &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; messages can be sent until the end of the stream is reached.  &amp;lt;tt&amp;gt;Metatext&amp;lt;/tt&amp;gt; messages (either &amp;lt;tt&amp;gt;Didl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Oh&amp;lt;/tt&amp;gt;) may be interleaved with &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; message implies that a break in audio may follow.  If this break is during a stream, the Sender must have applied attenuation to samples immediately before this to avoid any audio artifacts at the break in transmission.  Senders which cannot do this should implement pausing of streams using the Transport.Pause control API instead.&lt;br /&gt;
&lt;br /&gt;
The details of the wire protocol are shown below.  Note that all multi-byte integer values are big endian.&lt;br /&gt;
{|&lt;br /&gt;
! '''Bytes'''&lt;br /&gt;
! '''Name'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| '''Header'''&lt;br /&gt;
|&lt;br /&gt;
| Prefixes to all messages below&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Signature&lt;br /&gt;
| 0x73, 0x63, 0x64,0x20 ('scd ')&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Type&lt;br /&gt;
| The type of message:&lt;br /&gt;
* 0 – Ready&lt;br /&gt;
* 1 – MetadataDidl&lt;br /&gt;
* 2 - MetaDataOh&lt;br /&gt;
* 3 – Format&lt;br /&gt;
* 5 – Audio&lt;br /&gt;
* 7 – MetatextDidl&lt;br /&gt;
* 8 – MetatextOh&lt;br /&gt;
* 9 – Halt&lt;br /&gt;
* 10 – Disconnect&lt;br /&gt;
* 11 – Seek&lt;br /&gt;
* 12 – Skip&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Length&lt;br /&gt;
| Length in bytes of the whole message including this header&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Reserved&lt;br /&gt;
| Unused, reserved for future use&lt;br /&gt;
|-&lt;br /&gt;
| '''Ready'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Major Version&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Minor Version&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| TrackUriLength&lt;br /&gt;
| Length, in bytes, of the track URI&lt;br /&gt;
|-&lt;br /&gt;
| m&lt;br /&gt;
| TrackUri&lt;br /&gt;
| The track URI, where m = TrackUriLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| MetadataLength&lt;br /&gt;
| Length, in bytes, of the track metadata, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metadata&lt;br /&gt;
| The track metadata, where n = MetadataLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metadata element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metadata element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metadata elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Format'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| BitDepth&lt;br /&gt;
| Bit depth of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| SampleRate&lt;br /&gt;
| Sample rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Channels&lt;br /&gt;
| Number of channels of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| BitRate&lt;br /&gt;
| Bit rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SamplesTotal&lt;br /&gt;
| Total number of samples in the following audio (requirement for this to be confirmed)&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SampleStart&lt;br /&gt;
| Sample position of the first sample in the next &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; message&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Flags&lt;br /&gt;
|&lt;br /&gt;
* Bit 0 - Seekable&lt;br /&gt;
* Bit 1 - Lossless&lt;br /&gt;
* Bit 2 - Live (content generated upstream of the Sender, e.g. internet radio)&lt;br /&gt;
* Bit 3 - Broadcastable (whether the Receiver is allowed to offer the following audio via any multi-room protocols&lt;br /&gt;
* Bits 4-7 - Reserved.  Must be zero.&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| CodecNameLength&lt;br /&gt;
| Length, in bytes, of the codec name&lt;br /&gt;
|-&lt;br /&gt;
| r&lt;br /&gt;
| CodecName&lt;br /&gt;
| The codec name, where r = CodecNameLength&lt;br /&gt;
|-&lt;br /&gt;
| '''Audio'''&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| NumSamples&lt;br /&gt;
| The number of audio samples in this message&lt;br /&gt;
|-&lt;br /&gt;
| s&lt;br /&gt;
| AudioData&lt;br /&gt;
| Audio data.  Where s = NumSamples * (BitDepth/8) * NumChannels.&amp;lt;br&amp;gt;Multi-channel audio must supply data sample at a time, with left channel first.  Audio is packed (i.e. no padding bytes rounding samples up to 32-bit boundaries) and big endian.&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Metatext Length&lt;br /&gt;
| Length, in bytes, of the metatext, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metatext&lt;br /&gt;
| The metatext, where n = MetatextLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metatext element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metatext element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metatext elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Halt'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Disconnect'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Seek'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|-&lt;br /&gt;
| '''Skip'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av::OhMetadata</id>
		<title>Av::OhMetadata</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av::OhMetadata"/>
				<updated>2017-12-20T14:32:25Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* OpenHome Metadata Format */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Metadata Format =&lt;br /&gt;
OpenHome Metadata format describes metadata for an audio track as a series of key-value pairs.&lt;br /&gt;
&lt;br /&gt;
The list of supported keys, their mapping into DIDL-Lite and the number of instances that may be used are listed below:&lt;br /&gt;
{|&lt;br /&gt;
! '''Key'''&lt;br /&gt;
! '''DIDL-Lite mapping'''&lt;br /&gt;
! '''Instances'''&lt;br /&gt;
|-&lt;br /&gt;
| uri&lt;br /&gt;
| res&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| @id in item&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| &lt;br /&gt;
* track -&amp;gt; object.item.audioItem.musicTrack&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| provider&lt;br /&gt;
| oh:provider&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| title&lt;br /&gt;
| dc:title&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| artwork&lt;br /&gt;
| oh:artwork&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| artist&lt;br /&gt;
| upnp:artist&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| composer&lt;br /&gt;
| upnp:artist @role=composer&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| conductor&lt;br /&gt;
| upnp:artist @role=conductor&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| genre&lt;br /&gt;
| upnp:genre&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| albumTitle&lt;br /&gt;
| upnp:album&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| albumArtwork&lt;br /&gt;
| upnp:albumArtURI&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| albumArtist&lt;br /&gt;
| upnp:artist @role=AlbumArtist&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| albumGenre&lt;br /&gt;
| upnp:genre&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| year&lt;br /&gt;
| dc:date&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| disc&lt;br /&gt;
| oh:originalDiscNumber&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| discs&lt;br /&gt;
| oh:originalDiscCount&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| track&lt;br /&gt;
| upnp:originalTrackNumber&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| tracks&lt;br /&gt;
| oh:originalTrackCount&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| channels&lt;br /&gt;
| res @nrAudioChannels&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| bitDepth&lt;br /&gt;
| res @bitsPerSample&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| sampleRate&lt;br /&gt;
| res @sampleFrequency&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| bitRate&lt;br /&gt;
| res @bitrate (integer / string of digits)&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| duration&lt;br /&gt;
| res @duration (seconds - string of digits, zero = live/eternal)&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| mimeType&lt;br /&gt;
| res @protocolInfo&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| work&lt;br /&gt;
| oh:work&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| movement&lt;br /&gt;
| oh:movement&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| show&lt;br /&gt;
| oh:show&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| episode&lt;br /&gt;
| oh:episodeNumber&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| episodes&lt;br /&gt;
| oh:episodeCount&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| author&lt;br /&gt;
| dc:author&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| narrator&lt;br /&gt;
| upnp:artist @role=narrator&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| performer&lt;br /&gt;
| upnp:artist @role=performer&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| publisher&lt;br /&gt;
| dc:publisher&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| published&lt;br /&gt;
| oh:published (ISO 8601)&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| website&lt;br /&gt;
| oh:website&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| location&lt;br /&gt;
| oh:location (ISO 6709)&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| details&lt;br /&gt;
| oh:details&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| description&lt;br /&gt;
| dc:description&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| rating&lt;br /&gt;
| upnp:rating&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| extensions&lt;br /&gt;
| oh:extensions&lt;br /&gt;
| [0..1]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av::OhMetadata</id>
		<title>Av::OhMetadata</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av::OhMetadata"/>
				<updated>2017-12-20T14:24:03Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* OpenHome Metadata Format */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Metadata Format =&lt;br /&gt;
OpenHome Metadata format describes metadata for an audio track as a series of key-value pairs.&lt;br /&gt;
&lt;br /&gt;
The list of supported keys, their mapping into DIDL-Lite and the number of instances that may be used are listed below:&lt;br /&gt;
{|&lt;br /&gt;
! '''Key'''&lt;br /&gt;
! '''DIDL-Lite mapping'''&lt;br /&gt;
! '''Instances'''&lt;br /&gt;
|-&lt;br /&gt;
| uri&lt;br /&gt;
| res&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| @id in item&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| &lt;br /&gt;
* track -&amp;gt; object.item.audioItem.musicTrack&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| provider&lt;br /&gt;
| oh:provider&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| title&lt;br /&gt;
| dc:title&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| artwork&lt;br /&gt;
| oh:artwork&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| artist&lt;br /&gt;
| upnp:artist&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| composer&lt;br /&gt;
| upnp:artist @role=composer&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| conductor&lt;br /&gt;
| upnp:artist @role=conductor&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| genre&lt;br /&gt;
| upnp:genre&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| albumTitle&lt;br /&gt;
| upnp:album&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| albumArtwork&lt;br /&gt;
| upnp:albumArtURI&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| albumArtist&lt;br /&gt;
| upnp:artist @role=AlbumArtist&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| albumGenre&lt;br /&gt;
| upnp:genre&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| year&lt;br /&gt;
| dc:date&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| disc&lt;br /&gt;
| oh:originalDiscNumber&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| discs&lt;br /&gt;
| oh:originalDiscCount&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| track&lt;br /&gt;
| upnp:originalTrackNumber&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| tracks&lt;br /&gt;
| oh:originalTrackCount&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| channels&lt;br /&gt;
| res @nrAudioChannels&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| bitDepth&lt;br /&gt;
| res @bitsPerSample&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| sampleRate&lt;br /&gt;
| res @sampleFrequency&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| bitRate&lt;br /&gt;
| res @bitrate (integer)&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| duration&lt;br /&gt;
| res @duration (integer - seconds, zero = live/eternal)&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| mimeType&lt;br /&gt;
| res @protocolInfo&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| work&lt;br /&gt;
| oh:work&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| movement&lt;br /&gt;
| oh:movement&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| show&lt;br /&gt;
| oh:show&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| episode&lt;br /&gt;
| oh:episodeNumber&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| episodes&lt;br /&gt;
| oh:episodeCount&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| author&lt;br /&gt;
| dc:author&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| narrator&lt;br /&gt;
| upnp:artist @role=narrator&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| performer&lt;br /&gt;
| upnp:artist @role=performer&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| publisher&lt;br /&gt;
| dc:publisher&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| published&lt;br /&gt;
| oh:published (ISO 8601)&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| website&lt;br /&gt;
| oh:website&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| location&lt;br /&gt;
| oh:location (ISO 6709)&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| details&lt;br /&gt;
| oh:details&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| description&lt;br /&gt;
| dc:description&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| rating&lt;br /&gt;
| upnp:rating&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| extensions&lt;br /&gt;
| oh:extensions&lt;br /&gt;
| [0..1]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2017-07-18T11:14:56Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: v2 format&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
=== Framing ===&lt;br /&gt;
Each message, in either direction, is a JSON object followed by a newline (&amp;lt;tt&amp;gt;'\n'&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Announcement ===&lt;br /&gt;
When a client connects, a device announces its capabilities:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;:&amp;quot;announcement&amp;quot;,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;:2,&lt;br /&gt;
        &amp;quot;devices&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;:&amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service1&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service2&amp;quot;, &amp;quot;version&amp;quot;:2 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service3&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service4&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service5&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Control ===&lt;br /&gt;
The control point can invoke an action on a device as follows.  This will block until a response is sent.  Note that it is possible that the control point may receive other messages (e.g. &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt; - see below) before the action response.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each input argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;action&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 1 },&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;action_name&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
            ],&lt;br /&gt;
        &amp;quot;userAgent&amp;quot;:&amp;quot;optional client identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation is successful.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each output argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation fails:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Eventing ===&lt;br /&gt;
Subscribe to a particular service.  On successful completion, the device will send out unsolicited messages (with type &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt;) whenever one or more evented properties of a service change.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request succeeds.  The subscription id (sid) will be included in all later evented updates for this subscription.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request fails.  No later evented updates will be sent.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;sid&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Unsubscribe (halt a particular stream of evented updates).&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when an unsubscribe completes.  No evented updates for this subscription will be sent after this.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribeResponse&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A device will send the following whenever one or more evented properties change on a service with an active subscription.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each property will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for the associated &amp;lt;tt&amp;gt;stateVariable&amp;lt;/tt&amp;gt; in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;notify&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2017-07-18T11:14:26Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: v2 format for properties&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
=== Framing ===&lt;br /&gt;
Each message, in either direction, is a JSON object followed by a newline (&amp;lt;tt&amp;gt;'\n'&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Announcement ===&lt;br /&gt;
When a client connects, a device announces its capabilities:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;:&amp;quot;announcement&amp;quot;,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;:1,&lt;br /&gt;
        &amp;quot;devices&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;:&amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service1&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service2&amp;quot;, &amp;quot;version&amp;quot;:2 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service3&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service4&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service5&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Control ===&lt;br /&gt;
The control point can invoke an action on a device as follows.  This will block until a response is sent.  Note that it is possible that the control point may receive other messages (e.g. &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt; - see below) before the action response.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each input argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;action&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 1 },&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;action_name&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
            ],&lt;br /&gt;
        &amp;quot;userAgent&amp;quot;:&amp;quot;optional client identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation is successful.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each output argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation fails:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Eventing ===&lt;br /&gt;
Subscribe to a particular service.  On successful completion, the device will send out unsolicited messages (with type &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt;) whenever one or more evented properties of a service change.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request succeeds.  The subscription id (sid) will be included in all later evented updates for this subscription.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request fails.  No later evented updates will be sent.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;sid&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Unsubscribe (halt a particular stream of evented updates).&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when an unsubscribe completes.  No evented updates for this subscription will be sent after this.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribeResponse&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A device will send the following whenever one or more evented properties change on a service with an active subscription.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each property will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for the associated &amp;lt;tt&amp;gt;stateVariable&amp;lt;/tt&amp;gt; in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;notify&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;property_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2017-07-18T11:13:05Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: v2 format for arguments&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
=== Framing ===&lt;br /&gt;
Each message, in either direction, is a JSON object followed by a newline (&amp;lt;tt&amp;gt;'\n'&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Announcement ===&lt;br /&gt;
When a client connects, a device announces its capabilities:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;:&amp;quot;announcement&amp;quot;,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;:1,&lt;br /&gt;
        &amp;quot;devices&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;:&amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service1&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service2&amp;quot;, &amp;quot;version&amp;quot;:2 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service3&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service4&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service5&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Control ===&lt;br /&gt;
The control point can invoke an action on a device as follows.  This will block until a response is sent.  Note that it is possible that the control point may receive other messages (e.g. &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt; - see below) before the action response.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each input argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;action&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 1 },&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;action_name&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;input_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
            ],&lt;br /&gt;
        &amp;quot;userAgent&amp;quot;:&amp;quot;optional client identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation is successful.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each output argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: [&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_str&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;json_escaped_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bin&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;base64_encoded_str&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_bool&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;true&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_int&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;-1&amp;quot; },&lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;output_arg_uint&amp;quot;, &amp;quot;value&amp;quot;:&amp;quot;3&amp;quot; }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation fails:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Eventing ===&lt;br /&gt;
Subscribe to a particular service.  On successful completion, the device will send out unsolicited messages (with type &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt;) whenever one or more evented properties of a service change.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request succeeds.  The subscription id (sid) will be included in all later evented updates for this subscription.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request fails.  No later evented updates will be sent.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;sid&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Unsubscribe (halt a particular stream of evented updates).&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when an unsubscribe completes.  No evented updates for this subscription will be sent after this.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribeResponse&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A device will send the following whenever one or more evented properties change on a service with an active subscription.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each property will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for the associated &amp;lt;tt&amp;gt;stateVariable&amp;lt;/tt&amp;gt; in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;notify&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
            &amp;quot;property_str&amp;quot;:&amp;quot;json_escaped_str&amp;quot;,&lt;br /&gt;
            &amp;quot;property_bin&amp;quot;:&amp;quot;base64_encoded_str&amp;quot;,&lt;br /&gt;
            &amp;quot;property_bool&amp;quot;:&amp;quot;true&amp;quot;,&lt;br /&gt;
            &amp;quot;property_int&amp;quot;:&amp;quot;-1&amp;quot;,&lt;br /&gt;
            &amp;quot;property_uint&amp;quot;:&amp;quot;3&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2017-06-26T08:17:41Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Eventing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
=== Framing ===&lt;br /&gt;
Each message, in either direction, is a JSON object followed by a newline (&amp;lt;tt&amp;gt;'\n'&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Announcement ===&lt;br /&gt;
When a client connects, a device announces its capabilities:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;:&amp;quot;announcement&amp;quot;,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;:1,&lt;br /&gt;
        &amp;quot;devices&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;:&amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service1&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service2&amp;quot;, &amp;quot;version&amp;quot;:2 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service3&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service4&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service5&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Control ===&lt;br /&gt;
The control point can invoke an action on a device as follows.  This will block until a response is sent.  Note that it is possible that the control point may receive other messages (e.g. &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt; - see below) before the action response.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each input argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;action&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 1 },&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;action_name&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {&lt;br /&gt;
            &amp;quot;input_arg_str&amp;quot;:&amp;quot;json_escaped_str&amp;quot;,&lt;br /&gt;
            &amp;quot;input_arg_bin&amp;quot;:&amp;quot;base64_encoded_str&amp;quot;,&lt;br /&gt;
            &amp;quot;input_arg_bool&amp;quot;:&amp;quot;true&amp;quot;,&lt;br /&gt;
            &amp;quot;input_arg_int&amp;quot;:&amp;quot;-1&amp;quot;,&lt;br /&gt;
            &amp;quot;input_arg_uint&amp;quot;:&amp;quot;3&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        &amp;quot;userAgent&amp;quot;:&amp;quot;optional client identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation is successful.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each output argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {&lt;br /&gt;
            &amp;quot;output_arg_str&amp;quot;:&amp;quot;json_escaped_str&amp;quot;,&lt;br /&gt;
            &amp;quot;output_arg_bin&amp;quot;:&amp;quot;base64_encoded_str&amp;quot;,&lt;br /&gt;
            &amp;quot;output_arg_bool&amp;quot;:&amp;quot;true&amp;quot;,&lt;br /&gt;
            &amp;quot;output_arg_int&amp;quot;:&amp;quot;-1&amp;quot;,&lt;br /&gt;
            &amp;quot;output_arg_uint&amp;quot;:&amp;quot;3&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation fails:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Eventing ===&lt;br /&gt;
Subscribe to a particular service.  On successful completion, the device will send out unsolicited messages (with type &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt;) whenever one or more evented properties of a service change.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request succeeds.  The subscription id (sid) will be included in all later evented updates for this subscription.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request fails.  No later evented updates will be sent.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;sid&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Unsubscribe (halt a particular stream of evented updates).&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when an unsubscribe completes.  No evented updates for this subscription will be sent after this.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribeResponse&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A device will send the following whenever one or more evented properties change on a service with an active subscription.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each property will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for the associated &amp;lt;tt&amp;gt;stateVariable&amp;lt;/tt&amp;gt; in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;notify&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
            &amp;quot;property_str&amp;quot;:&amp;quot;json_escaped_str&amp;quot;,&lt;br /&gt;
            &amp;quot;property_bin&amp;quot;:&amp;quot;base64_encoded_str&amp;quot;,&lt;br /&gt;
            &amp;quot;property_bool&amp;quot;:&amp;quot;true&amp;quot;,&lt;br /&gt;
            &amp;quot;property_int&amp;quot;:&amp;quot;-1&amp;quot;,&lt;br /&gt;
            &amp;quot;property_uint&amp;quot;:&amp;quot;3&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Scd</id>
		<title>Av:Developer:Scd</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Scd"/>
				<updated>2017-06-26T08:15:47Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Protocol */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Songcast Direct =&lt;br /&gt;
== Overview ==&lt;br /&gt;
Songcast Direct (SCD) can be used to send decoded audio from any computing device to an OpenHome device.  The Sender device is responsible for decoding audio to PCM, framing this in a simple protocol and making it available via a simple TCP server.  The Receiver pulls data from this server, giving the Receiver complete control of the audio clock.&lt;br /&gt;
&lt;br /&gt;
A Songcast Direct sender performs a broadly similar role to a Songcast sender.  Applications that perform their own decoding to PCM will find SCD is easier to integrate and offers higher audio performance:&lt;br /&gt;
* There is a constant TCP connection between sender and receiver, avoiding the need for application-level resend support&lt;br /&gt;
* It uses the clock of the receiver, allowing for higher quality playback if the sender is on a desktop computer&lt;br /&gt;
* It offers the receiver limited control over the stream – initially seeking within a track or skipping between tracks.  While the primary control UI may reside on the sender device, this allows for integration with any Ir handset for the receiver.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd ohPipeline] contains sample code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;WavSender&amp;lt;/tt&amp;gt; contains an example of a trivial SCD Sender, scanning a single directory and decoding then sending any WAV files it finds. (Note that compilation of this is currently disabled.  &amp;lt;tt&amp;gt;DirScanner::Run()&amp;lt;/tt&amp;gt; contains code from an experimental precursor to C++17's &amp;lt;tt&amp;gt;std::filesystem::directory_iterator&amp;lt;/tt&amp;gt;.  Current code is compatible with VS2013; it should only require a couple of lines of change to make this compile against any more recent compiler.)&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd Scd] and [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd/Sender Sender] directories should be usable without any change.  It will be possible to write a commercial quality sender using the &amp;lt;tt&amp;gt;ScdSender&amp;lt;/tt&amp;gt; library, passing audio into &amp;lt;tt&amp;gt;IScdSupply&amp;lt;/tt&amp;gt; and relying on the configuration of &amp;lt;tt&amp;gt;ScdMsgFactory&amp;lt;/tt&amp;gt; to determine how much audio is buffered by the Sender.&lt;br /&gt;
&lt;br /&gt;
Sample code demonstrating how a Sender can control a Receiver via ODP is coming soon.  For now, see [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP tests] for a basic example.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
=== SSDP ===&lt;br /&gt;
First search for &amp;lt;tt&amp;gt;av-openhome-org:service:Product:2&amp;lt;/tt&amp;gt; then either&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Attributes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;Transport&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Transport&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;SourceXml&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; for a source with &amp;lt;tt&amp;gt;Type&amp;lt;/tt&amp;gt; of &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== mDNS ===&lt;br /&gt;
Search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; service to identify ODP endpoint&lt;br /&gt;
&lt;br /&gt;
== Control ==&lt;br /&gt;
Control of the Receiver is out of band, via the standard [[OhMediaDevelopers#Network_Services | OpenHome network APIs]].  These are available over UPnP or [[OhMediaDevelopers#ODP | ODP]] (a single connected socket).&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
The protocol used for communication between Sender and Receiver contains the following message types:&lt;br /&gt;
{|&lt;br /&gt;
! '''Type'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
! '''Sent by'''&lt;br /&gt;
|-&lt;br /&gt;
| Ready&lt;br /&gt;
| Signals availability and version support to other party&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataDidl &lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataOh&lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Format&lt;br /&gt;
| Format for the following audio. Must be sent before any audio.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Audio&lt;br /&gt;
| Decoded audio.  Can only be sent after a &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; message describing  its sample rate etc.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextDidl&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextOh&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Halt&lt;br /&gt;
| Indicates that a break in audio follows.  E.g. at the end of a track with no further tracks to be played, or when the Sender has paused.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Disconnect&lt;br /&gt;
| Indicates that the originator of the message is closing its SCD session. No further audio will be available. The message receiver should disconnect its socket.&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| Seek&lt;br /&gt;
| Indicates that the Receiver wants to jump to a different point in the current track.&amp;lt;br&amp;gt;Is only sent for tracks that the Sender has indicated support seeking.&lt;br /&gt;
| Receiver&lt;br /&gt;
|-&lt;br /&gt;
| Skip&lt;br /&gt;
| Indicates that the Receiver wants to immediately jump to the next or previous track.&lt;br /&gt;
| Receiver&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A SCD session is initiated by the Sender.  It instantiates a simple TCP server then instructs the Receiver to start playing from it.&lt;br /&gt;
&lt;br /&gt;
The Receiver connects to the Sender and sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, indicating the protocol version it supports.  If the Sender is compatible with this version, it responds with a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the same version.  Otherwise, the Sender sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the version it supports.  If the Receiver cannot support this version, it must close the connection.&lt;br /&gt;
&lt;br /&gt;
After sending a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, the Sender should send either &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; (if it has nothing to send yet) or one of &amp;lt;tt&amp;gt;MetadataDidl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;MetadataOh&amp;lt;/tt&amp;gt; plus &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt;.  The order of &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; versus &amp;lt;tt&amp;gt;Metadata*&amp;lt;/tt&amp;gt; is not important.&lt;br /&gt;
&lt;br /&gt;
After this, the Sender should then send &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.  Any number of &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; messages can be sent until the end of the stream is reached.  &amp;lt;tt&amp;gt;Metatext&amp;lt;/tt&amp;gt; messages (either &amp;lt;tt&amp;gt;Didl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Oh&amp;lt;/tt&amp;gt;) may be interleaved with &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; message implies that a break in audio may follow.  If this break is during a stream, the Sender must have applied attenuation to samples immediately before this to avoid any audio artifacts at the break in transmission.  Senders which cannot do this should implement pausing of streams using the Transport.Pause control API instead.&lt;br /&gt;
&lt;br /&gt;
The details of the wire protocol are shown below.  Note that all multi-byte integer values are big endian.&lt;br /&gt;
{|&lt;br /&gt;
! '''Bytes'''&lt;br /&gt;
! '''Name'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| '''Header'''&lt;br /&gt;
|&lt;br /&gt;
| Prefixes to all messages below&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Signature&lt;br /&gt;
| 0x73, 0x63, 0x64,0x20 ('scd ')&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Type&lt;br /&gt;
| The type of message:&lt;br /&gt;
* 0 – Ready&lt;br /&gt;
* 1 – MetadataDidl&lt;br /&gt;
* 2 - MetaDataOh&lt;br /&gt;
* 3 – Format&lt;br /&gt;
* 5 – Audio&lt;br /&gt;
* 7 – MetatextDidl&lt;br /&gt;
* 8 – MetatextOh&lt;br /&gt;
* 9 – Halt&lt;br /&gt;
* 10 – Disconnect&lt;br /&gt;
* 11 – Seek&lt;br /&gt;
* 12 – Skip&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Length&lt;br /&gt;
| Length in bytes of the whole message including this header&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Reserved&lt;br /&gt;
| Unused, reserved for future use&lt;br /&gt;
|-&lt;br /&gt;
| '''Ready'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Major Version&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Minor Version&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| TrackUriLength&lt;br /&gt;
| Length, in bytes, of the track URI&lt;br /&gt;
|-&lt;br /&gt;
| m&lt;br /&gt;
| TrackUri&lt;br /&gt;
| The track URI, where m = TrackUriLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| MetadataLength&lt;br /&gt;
| Length, in bytes, of the track metadata, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metadata&lt;br /&gt;
| The track metadata, where n = MetadataLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metadata element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metadata element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metadata elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Format'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| BitDepth&lt;br /&gt;
| Bit depth of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| SampleRate&lt;br /&gt;
| Sample rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Channels&lt;br /&gt;
| Number of channels of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| BitRate&lt;br /&gt;
| Bit rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SamplesTotal&lt;br /&gt;
| Total number of samples in the following audio (requirement for this to be confirmed)&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SampleStart&lt;br /&gt;
| Sample position of the first sample in the next &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; message&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Flags&lt;br /&gt;
|&lt;br /&gt;
* Bit 0 - Seekable&lt;br /&gt;
* Bit 1 - Lossless&lt;br /&gt;
* Bit 2 - Live (content generated upstream of the Sender, e.g. internet radio)&lt;br /&gt;
* Bit 3 - Broadcastable (whether the Receiver is allowed to offer the following audio via any multi-room protocols&lt;br /&gt;
* Bits 4-7 - Reserved.  Must be zero.&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| CodecNameLength&lt;br /&gt;
| Length, in bytes, of the codec name&lt;br /&gt;
|-&lt;br /&gt;
| r&lt;br /&gt;
| CodecName&lt;br /&gt;
| The codec name, where r = CodecNameLength&lt;br /&gt;
|-&lt;br /&gt;
| '''Audio'''&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| NumSamples&lt;br /&gt;
| The number of audio samples in this message&lt;br /&gt;
|-&lt;br /&gt;
| s&lt;br /&gt;
| AudioData&lt;br /&gt;
| Audio data.  Where s = NumSamples * (BitDepth/8) * NumChannels.&amp;lt;br&amp;gt;Multi-channel audio must supply data sample at a time, with left channel first.  Audio is packed (i.e. no padding bytes rounding samples up to 32-bit boundaries) and big endian.&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Metatext Length&lt;br /&gt;
| Length, in bytes, of the metatext, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metatext&lt;br /&gt;
| The metatext, where n = MetatextLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metatext element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metatext element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metatext elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Halt'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Disconnect'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Seek'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|-&lt;br /&gt;
| '''Skip'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av::OhMetadata</id>
		<title>Av::OhMetadata</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av::OhMetadata"/>
				<updated>2017-06-23T15:39:00Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Created page with &amp;quot;= OpenHome Metadata Format = OpenHome Metadata format describes metadata for an audio track as a series of key-value pairs.  The list of supported keys, their mapping into DIDL-L...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Metadata Format =&lt;br /&gt;
OpenHome Metadata format describes metadata for an audio track as a series of key-value pairs.&lt;br /&gt;
&lt;br /&gt;
The list of supported keys, their mapping into DIDL-Lite and the number of instances that may be used are listed below:&lt;br /&gt;
{|&lt;br /&gt;
! '''Key'''&lt;br /&gt;
! '''DIDL-Lite mapping'''&lt;br /&gt;
! '''Instances'''&lt;br /&gt;
|-&lt;br /&gt;
| uri&lt;br /&gt;
| res&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| @id in item&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| &lt;br /&gt;
* track -&amp;gt; object.item.audioItem.musicTrack&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| provider&lt;br /&gt;
| oh:provider&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| title&lt;br /&gt;
| dc:title&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| artwork&lt;br /&gt;
| oh:artwork&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| artist&lt;br /&gt;
| upnp:artist&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| composer&lt;br /&gt;
| upnp:artist @role=composer&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| conductor&lt;br /&gt;
| upnp:artist @role=conductor&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| genre&lt;br /&gt;
| upnp:genre&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| albumTitle&lt;br /&gt;
| upnp:album&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| albumArtwork&lt;br /&gt;
| upnp:albumArtURI&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| albumArtist&lt;br /&gt;
| upnp:artist @role=AlbumArtist&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| albumGenre&lt;br /&gt;
| upnp:genre&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| year&lt;br /&gt;
| dc:date&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| disc&lt;br /&gt;
| oh:originalDiscNumber&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| discs&lt;br /&gt;
| oh:originalDiscCount&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| track&lt;br /&gt;
| upnp:originalTrackNumber&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| tracks&lt;br /&gt;
| oh:originalTrackCount&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| channels&lt;br /&gt;
| res @nrAudioChannels&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| bitDepth&lt;br /&gt;
| res @bitsPerSample&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| sampleRate&lt;br /&gt;
| res @sampleFrequency&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| bitRate&lt;br /&gt;
| res @bitrate&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| duration&lt;br /&gt;
| res @duration (seconds, zero = live/eternal)&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| mimeType&lt;br /&gt;
| res @protocolInfo&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| work&lt;br /&gt;
| oh:work&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| movement&lt;br /&gt;
| oh:movement&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| show&lt;br /&gt;
| oh:show&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| episode&lt;br /&gt;
| oh:episodeNumber&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| episodes&lt;br /&gt;
| oh:episodeCount&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| author&lt;br /&gt;
| dc:author&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| narrator&lt;br /&gt;
| upnp:artist @role=narrator&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| performer&lt;br /&gt;
| upnp:artist @role=performer&lt;br /&gt;
| [0..n]&lt;br /&gt;
|-&lt;br /&gt;
| publisher&lt;br /&gt;
| dc:publisher&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| published&lt;br /&gt;
| oh:published (ISO 8601)&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| website&lt;br /&gt;
| oh:website&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| location&lt;br /&gt;
| oh:location (ISO 6709)&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| details&lt;br /&gt;
| oh:details&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| description&lt;br /&gt;
| dc:description&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| rating&lt;br /&gt;
| upnp:rating&lt;br /&gt;
| [0..1]&lt;br /&gt;
|-&lt;br /&gt;
| extensions&lt;br /&gt;
| oh:extensions&lt;br /&gt;
| [0..1]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhMediaDevelopers</id>
		<title>OhMediaDevelopers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhMediaDevelopers"/>
				<updated>2017-06-23T15:07:49Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Direct */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Network Services =&lt;br /&gt;
ohMedia defines the following network services:&lt;br /&gt;
* [[Av:Developer:ProductService | Product]].  The core of a renderer and the only mandatory service.  The state of this service allows control points to infer which other services are present on a device.  In more complex installations it allows devices to mapped into a multi-room hi-fi system&lt;br /&gt;
* [[Av:Developer:PlaylistService | Playlist]].  An ordered list of tracks to be played.&lt;br /&gt;
* [[Av:Developer:RadioService | Radio]].  Browse and select from a list of favourite internet radio, podcast and listen again presets.&lt;br /&gt;
* [[Av:Developer:InfoService | Info]].  Report information about currently playing track.&lt;br /&gt;
* [[Av:Developer:TimeService | Time]].  Report information about progress through a track.&lt;br /&gt;
* [[Av:Developer:VolumeService | Volume]].  Control volume on a renderer or a connected pre-amp.&lt;br /&gt;
* [[Av:Developer:TransportService | Transport]].  Source-independent transport controls.&lt;br /&gt;
* [[Av:Developer:SenderService | Sender]].  Indicate presence and state of a Songcast sender.&lt;br /&gt;
* [[Av:Developer:ReceiverService | Receiver]].  Control a Songcast receiver.&lt;br /&gt;
* [[Av:Developer:CredentialsService | Credentials]].  Securely manage login details for external services supported by a device.&lt;br /&gt;
* NetworkMonitor.  Measures network performance.&lt;br /&gt;
* [[Av:Developer:PlaylistManagerService | PlaylistManager]].  Included in media servers.  Allows playlists to be shared between renderers and saved for future reuse.&lt;br /&gt;
&lt;br /&gt;
The [[Av:Developer:EriskayServices | Eriskay]] family of services will later replace these.  Feedback on Eriskay is welcomed.&lt;br /&gt;
&lt;br /&gt;
= UPnP =&lt;br /&gt;
All ohMedia products publish and/or consume network services using UPnP.  This is enabled by [[OhNet | ohNet]] - a cross-platform UPnP stack suitable for use in control points and devices.  ohNet is open source, liberally licensed and intended for use in external products.&lt;br /&gt;
&lt;br /&gt;
= ODP =&lt;br /&gt;
[[Av:Developer:Odp | OpenHome Device Protocol]] (ODP) allows control of and evented updates from a device via a single socket.  [https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
All services that are available using over UPnP are also available using ODP.  The same auto-generated 'proxies' allow control point authors to invoke an action as a single function call and register callbacks to be informed of evented updates.&lt;br /&gt;
&lt;br /&gt;
= Songcast =&lt;br /&gt;
The Songcast brand encompasses a range of products and protocols.&lt;br /&gt;
&lt;br /&gt;
== Desktop senders ==&lt;br /&gt;
Virtual audio drivers that send all audio from a Windows or Mac device to a songcast receiver.  [https://www.linn.co.uk/software#songcast Linn] provide a full implementation of these.  The bulk of the code required is also available in the [https://github.com/openhome/ohSongcast ohSongcast] repo.&lt;br /&gt;
&lt;br /&gt;
== Multi-room ==&lt;br /&gt;
The Songcast protocol enables synchronised playing of audio from an unbounded number of ohMedia renderers.&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/openhome/ohSongcast ohSongcast] repo provides a cross-platform C++ library offering much of the code needed to write a stand-alone songcast sender.  The [https://github.com/openhome/ohPipeline ohPipeline] repo contains a reference sender and receiver fully integrated to the OpenHome reference audio pipeline.&lt;br /&gt;
&lt;br /&gt;
The Songcast protocols are also documented:&lt;br /&gt;
* [[Av:Developer:Songcast:Ohm | OHM/OHU protocol specification]]&lt;br /&gt;
* [[Av:Developer:Songcast:Ohz | OHZ protocol specification]]&lt;br /&gt;
&lt;br /&gt;
== Direct ==&lt;br /&gt;
A specialised protocol, offering simpler integration and potentially higher audio quality, used when there is a single receiver and the sender has control over the rate of streaming (this often means that the sender is responsible for audio decode).&lt;br /&gt;
&lt;br /&gt;
More information, including protocol spec and sample code is available [[Av:Developer:Scd | here]].&lt;br /&gt;
&lt;br /&gt;
= Topology =&lt;br /&gt;
ohMedia models a home as a number of hi-fi systems, which are located in rooms.&lt;br /&gt;
&lt;br /&gt;
A hi-fi system is modelled as a hierarchical tree of products, where a product is defined as a single physical box that is located in a room, has a unique name within the room, has at least one output and any number of inputs.&lt;br /&gt;
&lt;br /&gt;
A product is modelled through the [[Av:Developer:ProductService | Product]] service specification.&lt;br /&gt;
&lt;br /&gt;
When a control point wants to construct a model of a user's home they use the Topology algorithm:&lt;br /&gt;
* discover all the products in the home that have a Product service&lt;br /&gt;
* group the discovered products based on the room they are in&lt;br /&gt;
* create a hierarchical tree structure by matching source names to product names *&lt;br /&gt;
* discover source functionality based on source type&lt;br /&gt;
* discover additional functionality based on product attributes&lt;br /&gt;
Example implementations of the Topology algorithm are available in C# and C++ from the [https://github.com/openhome/ohTopology ohTopology] github repo.&lt;br /&gt;
&lt;br /&gt;
A more detailed description of the ohTopology software can be found [[Av:Developer:ohTopologyDescription | here]].&lt;br /&gt;
&lt;br /&gt;
= Streaming Services =&lt;br /&gt;
Both Linn's DS  and [[OhMediaPlayer | ohMediaPlayer]] include reference implementations for the following streaming services:&lt;br /&gt;
* [[TidalStreamingService | Tidal]]&lt;br /&gt;
* [[QobuzStreamingService | Qobuz]]&lt;br /&gt;
* [[CalmRadioInternetRadio | Calm Radio]]&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhMediaDevelopers</id>
		<title>OhMediaDevelopers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhMediaDevelopers"/>
				<updated>2017-06-23T15:07:28Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Direct */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Network Services =&lt;br /&gt;
ohMedia defines the following network services:&lt;br /&gt;
* [[Av:Developer:ProductService | Product]].  The core of a renderer and the only mandatory service.  The state of this service allows control points to infer which other services are present on a device.  In more complex installations it allows devices to mapped into a multi-room hi-fi system&lt;br /&gt;
* [[Av:Developer:PlaylistService | Playlist]].  An ordered list of tracks to be played.&lt;br /&gt;
* [[Av:Developer:RadioService | Radio]].  Browse and select from a list of favourite internet radio, podcast and listen again presets.&lt;br /&gt;
* [[Av:Developer:InfoService | Info]].  Report information about currently playing track.&lt;br /&gt;
* [[Av:Developer:TimeService | Time]].  Report information about progress through a track.&lt;br /&gt;
* [[Av:Developer:VolumeService | Volume]].  Control volume on a renderer or a connected pre-amp.&lt;br /&gt;
* [[Av:Developer:TransportService | Transport]].  Source-independent transport controls.&lt;br /&gt;
* [[Av:Developer:SenderService | Sender]].  Indicate presence and state of a Songcast sender.&lt;br /&gt;
* [[Av:Developer:ReceiverService | Receiver]].  Control a Songcast receiver.&lt;br /&gt;
* [[Av:Developer:CredentialsService | Credentials]].  Securely manage login details for external services supported by a device.&lt;br /&gt;
* NetworkMonitor.  Measures network performance.&lt;br /&gt;
* [[Av:Developer:PlaylistManagerService | PlaylistManager]].  Included in media servers.  Allows playlists to be shared between renderers and saved for future reuse.&lt;br /&gt;
&lt;br /&gt;
The [[Av:Developer:EriskayServices | Eriskay]] family of services will later replace these.  Feedback on Eriskay is welcomed.&lt;br /&gt;
&lt;br /&gt;
= UPnP =&lt;br /&gt;
All ohMedia products publish and/or consume network services using UPnP.  This is enabled by [[OhNet | ohNet]] - a cross-platform UPnP stack suitable for use in control points and devices.  ohNet is open source, liberally licensed and intended for use in external products.&lt;br /&gt;
&lt;br /&gt;
= ODP =&lt;br /&gt;
[[Av:Developer:Odp | OpenHome Device Protocol]] (ODP) allows control of and evented updates from a device via a single socket.  [https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
All services that are available using over UPnP are also available using ODP.  The same auto-generated 'proxies' allow control point authors to invoke an action as a single function call and register callbacks to be informed of evented updates.&lt;br /&gt;
&lt;br /&gt;
= Songcast =&lt;br /&gt;
The Songcast brand encompasses a range of products and protocols.&lt;br /&gt;
&lt;br /&gt;
== Desktop senders ==&lt;br /&gt;
Virtual audio drivers that send all audio from a Windows or Mac device to a songcast receiver.  [https://www.linn.co.uk/software#songcast Linn] provide a full implementation of these.  The bulk of the code required is also available in the [https://github.com/openhome/ohSongcast ohSongcast] repo.&lt;br /&gt;
&lt;br /&gt;
== Multi-room ==&lt;br /&gt;
The Songcast protocol enables synchronised playing of audio from an unbounded number of ohMedia renderers.&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/openhome/ohSongcast ohSongcast] repo provides a cross-platform C++ library offering much of the code needed to write a stand-alone songcast sender.  The [https://github.com/openhome/ohPipeline ohPipeline] repo contains a reference sender and receiver fully integrated to the OpenHome reference audio pipeline.&lt;br /&gt;
&lt;br /&gt;
The Songcast protocols are also documented:&lt;br /&gt;
* [[Av:Developer:Songcast:Ohm | OHM/OHU protocol specification]]&lt;br /&gt;
* [[Av:Developer:Songcast:Ohz | OHZ protocol specification]]&lt;br /&gt;
&lt;br /&gt;
== Direct ==&lt;br /&gt;
A specialised protocol, offering simpler integration and potentially higher audio quality, used when there is a single receiver and the sender has control over the rate of streaming (this often means that the sender is responsible for audio decode).  More information, including protocol spec and sample code is available [[Av:Developer:Scd | here]].&lt;br /&gt;
&lt;br /&gt;
= Topology =&lt;br /&gt;
ohMedia models a home as a number of hi-fi systems, which are located in rooms.&lt;br /&gt;
&lt;br /&gt;
A hi-fi system is modelled as a hierarchical tree of products, where a product is defined as a single physical box that is located in a room, has a unique name within the room, has at least one output and any number of inputs.&lt;br /&gt;
&lt;br /&gt;
A product is modelled through the [[Av:Developer:ProductService | Product]] service specification.&lt;br /&gt;
&lt;br /&gt;
When a control point wants to construct a model of a user's home they use the Topology algorithm:&lt;br /&gt;
* discover all the products in the home that have a Product service&lt;br /&gt;
* group the discovered products based on the room they are in&lt;br /&gt;
* create a hierarchical tree structure by matching source names to product names *&lt;br /&gt;
* discover source functionality based on source type&lt;br /&gt;
* discover additional functionality based on product attributes&lt;br /&gt;
Example implementations of the Topology algorithm are available in C# and C++ from the [https://github.com/openhome/ohTopology ohTopology] github repo.&lt;br /&gt;
&lt;br /&gt;
A more detailed description of the ohTopology software can be found [[Av:Developer:ohTopologyDescription | here]].&lt;br /&gt;
&lt;br /&gt;
= Streaming Services =&lt;br /&gt;
Both Linn's DS  and [[OhMediaPlayer | ohMediaPlayer]] include reference implementations for the following streaming services:&lt;br /&gt;
* [[TidalStreamingService | Tidal]]&lt;br /&gt;
* [[QobuzStreamingService | Qobuz]]&lt;br /&gt;
* [[CalmRadioInternetRadio | Calm Radio]]&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2017-06-23T14:51:31Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Protocol */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
=== Framing ===&lt;br /&gt;
Each message, in either direction, is a JSON object followed by a newline (&amp;lt;tt&amp;gt;'\n'&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== Announcement ===&lt;br /&gt;
When a client connects, a device announces its capabilities:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;:&amp;quot;announcement&amp;quot;,&lt;br /&gt;
        &amp;quot;protocolVersion&amp;quot;:1,&lt;br /&gt;
        &amp;quot;devices&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;:&amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service1&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service2&amp;quot;, &amp;quot;version&amp;quot;:2 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service3&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: &amp;quot;udn&amp;quot;,&lt;br /&gt;
                &amp;quot;type&amp;quot;:&amp;quot;one of Ds / MediaRenderer / Preamp&amp;quot;,&lt;br /&gt;
                &amp;quot;services&amp;quot;: [&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service4&amp;quot;, &amp;quot;version&amp;quot;:1 },&lt;br /&gt;
                    { &amp;quot;name&amp;quot;:&amp;quot;service5&amp;quot;, &amp;quot;version&amp;quot;:1 }&lt;br /&gt;
                ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Control ===&lt;br /&gt;
The control point can invoke an action on a device as follows.  This will block until a response is sent.  Note that it is possible that the control point may receive other messages (e.g. &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt; - see below) before the action response.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each input argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;action&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 1 },&lt;br /&gt;
        &amp;quot;action&amp;quot;: &amp;quot;action_name&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {&lt;br /&gt;
            &amp;quot;input_arg_str&amp;quot;:&amp;quot;json_escaped_str&amp;quot;,&lt;br /&gt;
            &amp;quot;input_arg_bin&amp;quot;:&amp;quot;base64_encoded_str&amp;quot;,&lt;br /&gt;
            &amp;quot;input_arg_bool&amp;quot;:&amp;quot;true&amp;quot;,&lt;br /&gt;
            &amp;quot;input_arg_int&amp;quot;:&amp;quot;-1&amp;quot;,&lt;br /&gt;
            &amp;quot;input_arg_uint&amp;quot;:&amp;quot;3&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        &amp;quot;userAgent&amp;quot;:&amp;quot;optional client identifier&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation is successful.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each output argument will match the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element for that argument in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {&lt;br /&gt;
            &amp;quot;output_arg_str&amp;quot;:&amp;quot;json_escaped_str&amp;quot;,&lt;br /&gt;
            &amp;quot;output_arg_bin&amp;quot;:&amp;quot;base64_encoded_str&amp;quot;,&lt;br /&gt;
            &amp;quot;output_arg_bool&amp;quot;:&amp;quot;true&amp;quot;,&lt;br /&gt;
            &amp;quot;output_arg_int&amp;quot;:&amp;quot;-1&amp;quot;,&lt;br /&gt;
            &amp;quot;output_arg_uint&amp;quot;:&amp;quot;3&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when action invocation fails:&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;actionResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Eventing ===&lt;br /&gt;
Subscribe to a particular service.  On successful completion, the device will send out unsolicited messages (with type &amp;lt;tt&amp;gt;notify&amp;lt;/tt&amp;gt;) whenever one or more evented properties of a service change.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request succeeds.  The subscription id (sid) will be included in all later evented updates for this subscription.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: null,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when a subscribe request fails.  No later evented updates will be sent.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;subscribeResponse&amp;quot;,&lt;br /&gt;
        &amp;quot;device&amp;quot;: &amp;quot;type&amp;quot;,&lt;br /&gt;
        &amp;quot;service&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;service_name&amp;quot;, &amp;quot;version&amp;quot;: 2 }&lt;br /&gt;
        &amp;quot;error&amp;quot;: { &amp;quot;code&amp;quot;: 123, &amp;quot;description&amp;quot;: &amp;quot;error msg&amp;quot; },&lt;br /&gt;
        &amp;quot;sid&amp;quot;: null&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Unsubscribe (halt a particular stream of evented updates).&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribe&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Response when an unsubscribe completes.  No evented updates for this subscription will be sent after this.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;unsubscribeResponse&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A device will send the following whenever one or more evented properties change on a service with an active subscription.&lt;br /&gt;
&amp;lt;br&amp;gt;The name for each property will match the &amp;lt;tt&amp;gt;name&amp;lt;tt&amp;gt; element for the associated &amp;lt;tt&amp;gt;stateVariable&amp;lt;tt&amp;gt; in the service description XML.  All values are strings.&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;notify&amp;quot;,&lt;br /&gt;
        &amp;quot;sid&amp;quot;: &amp;quot;subscription_id&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
            &amp;quot;property_str&amp;quot;:&amp;quot;json_escaped_str&amp;quot;,&lt;br /&gt;
            &amp;quot;property_bin&amp;quot;:&amp;quot;base64_encoded_str&amp;quot;,&lt;br /&gt;
            &amp;quot;property_bool&amp;quot;:&amp;quot;true&amp;quot;,&lt;br /&gt;
            &amp;quot;property_int&amp;quot;:&amp;quot;-1&amp;quot;,&lt;br /&gt;
            &amp;quot;property_uint&amp;quot;:&amp;quot;3&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Odp</id>
		<title>Av:Developer:Odp</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Odp"/>
				<updated>2017-06-23T14:40:01Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Created page with &amp;quot;= OpenHome Device Protocol = == Overview == OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenHome Device Protocol =&lt;br /&gt;
== Overview ==&lt;br /&gt;
OpenHome Device Protocl (ODP) allows a control point to control and receive evented updates from an OpenHome device using a single TCP socket.  This has some advantages over UPnP:&lt;br /&gt;
* No need to define error handling policy for cases where evented updates cannot be delivered.&amp;lt;br&amp;gt;If the socket connection is open, it'll be possible to deliver an evented update.&amp;lt;br&amp;gt;If the socket connection is broken, the device can automatically clean up all subscriptions from that control point.&lt;br /&gt;
* No need to define additional protocol to allow control points to infer removal of a device.&amp;lt;br&amp;gt;If the socket connection is open, a control point can assume the device is available.&amp;lt;br&amp;gt;If the socket connection is broken, the control point is immediately prompted to retry connection; if this fails, it can quickly update its state to show that the device is no longer available.&lt;br /&gt;
* No danger of TIME_WAIT socket errors when control points invoke very large numbers of actions and/or devices are rebooted.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
Using mDNS, search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; to identify an ODP endpoint.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
Control point authors can instantiate [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/CpiDeviceOdp.h CpiDeviceOdp] then use standard ohNet proxy classes to access all OpenHome network services.  Proxies can be generated from UPnP service XML; pre-generated versions are available in [https://github.com/openhome/ohNetGenerated ohNetGenerated].&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP test code] for a simple example of a control point invoking actions and receiving evented updates over ODP.&lt;br /&gt;
&lt;br /&gt;
Sample code for mDNS discovery of ODP devices is coming soon.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhMediaDevelopers</id>
		<title>OhMediaDevelopers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhMediaDevelopers"/>
				<updated>2017-06-23T14:35:14Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Network Services =&lt;br /&gt;
ohMedia defines the following network services:&lt;br /&gt;
* [[Av:Developer:ProductService | Product]].  The core of a renderer and the only mandatory service.  The state of this service allows control points to infer which other services are present on a device.  In more complex installations it allows devices to mapped into a multi-room hi-fi system&lt;br /&gt;
* [[Av:Developer:PlaylistService | Playlist]].  An ordered list of tracks to be played.&lt;br /&gt;
* [[Av:Developer:RadioService | Radio]].  Browse and select from a list of favourite internet radio, podcast and listen again presets.&lt;br /&gt;
* [[Av:Developer:InfoService | Info]].  Report information about currently playing track.&lt;br /&gt;
* [[Av:Developer:TimeService | Time]].  Report information about progress through a track.&lt;br /&gt;
* [[Av:Developer:VolumeService | Volume]].  Control volume on a renderer or a connected pre-amp.&lt;br /&gt;
* [[Av:Developer:TransportService | Transport]].  Source-independent transport controls.&lt;br /&gt;
* [[Av:Developer:SenderService | Sender]].  Indicate presence and state of a Songcast sender.&lt;br /&gt;
* [[Av:Developer:ReceiverService | Receiver]].  Control a Songcast receiver.&lt;br /&gt;
* [[Av:Developer:CredentialsService | Credentials]].  Securely manage login details for external services supported by a device.&lt;br /&gt;
* NetworkMonitor.  Measures network performance.&lt;br /&gt;
* [[Av:Developer:PlaylistManagerService | PlaylistManager]].  Included in media servers.  Allows playlists to be shared between renderers and saved for future reuse.&lt;br /&gt;
&lt;br /&gt;
The [[Av:Developer:EriskayServices | Eriskay]] family of services will later replace these.  Feedback on Eriskay is welcomed.&lt;br /&gt;
&lt;br /&gt;
= UPnP =&lt;br /&gt;
All ohMedia products publish and/or consume network services using UPnP.  This is enabled by [[OhNet | ohNet]] - a cross-platform UPnP stack suitable for use in control points and devices.  ohNet is open source, liberally licensed and intended for use in external products.&lt;br /&gt;
&lt;br /&gt;
= ODP =&lt;br /&gt;
[[Av:Developer:Odp | OpenHome Device Protocol]] (ODP) allows control of and evented updates from a device via a single socket.  [https://github.com/openhome/ohPipeline ohPipeline] contains [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Net/Odp reference code] for control point or device stacks.&lt;br /&gt;
&lt;br /&gt;
All services that are available using over UPnP are also available using ODP.  The same auto-generated 'proxies' allow control point authors to invoke an action as a single function call and register callbacks to be informed of evented updates.&lt;br /&gt;
&lt;br /&gt;
= Songcast =&lt;br /&gt;
The Songcast brand encompasses a range of products and protocols.&lt;br /&gt;
&lt;br /&gt;
== Desktop senders ==&lt;br /&gt;
Virtual audio drivers that send all audio from a Windows or Mac device to a songcast receiver.  [https://www.linn.co.uk/software#songcast Linn] provide a full implementation of these.  The bulk of the code required is also available in the [https://github.com/openhome/ohSongcast ohSongcast] repo.&lt;br /&gt;
&lt;br /&gt;
== Multi-room ==&lt;br /&gt;
The Songcast protocol enables synchronised playing of audio from an unbounded number of ohMedia renderers.&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/openhome/ohSongcast ohSongcast] repo provides a cross-platform C++ library offering much of the code needed to write a stand-alone songcast sender.  The [https://github.com/openhome/ohPipeline ohPipeline] repo contains a reference sender and receiver fully integrated to the OpenHome reference audio pipeline.&lt;br /&gt;
&lt;br /&gt;
The Songcast protocols are also documented:&lt;br /&gt;
* [[Av:Developer:Songcast:Ohm | OHM/OHU protocol specification]]&lt;br /&gt;
* [[Av:Developer:Songcast:Ohz | OHZ protocol specification]]&lt;br /&gt;
&lt;br /&gt;
== Direct ==&lt;br /&gt;
A specialised protocol used when there is a single receiver and the sender has control over the rate of streaming (this often means that the sender is responsible for audio decode).  More information, including protocol spec and sample code is available [[Av:Developer:Scd | here]].&lt;br /&gt;
&lt;br /&gt;
= Topology =&lt;br /&gt;
ohMedia models a home as a number of hi-fi systems, which are located in rooms.&lt;br /&gt;
&lt;br /&gt;
A hi-fi system is modelled as a hierarchical tree of products, where a product is defined as a single physical box that is located in a room, has a unique name within the room, has at least one output and any number of inputs.&lt;br /&gt;
&lt;br /&gt;
A product is modelled through the [[Av:Developer:ProductService | Product]] service specification.&lt;br /&gt;
&lt;br /&gt;
When a control point wants to construct a model of a user's home they use the Topology algorithm:&lt;br /&gt;
* discover all the products in the home that have a Product service&lt;br /&gt;
* group the discovered products based on the room they are in&lt;br /&gt;
* create a hierarchical tree structure by matching source names to product names *&lt;br /&gt;
* discover source functionality based on source type&lt;br /&gt;
* discover additional functionality based on product attributes&lt;br /&gt;
Example implementations of the Topology algorithm are available in C# and C++ from the [https://github.com/openhome/ohTopology ohTopology] github repo.&lt;br /&gt;
&lt;br /&gt;
A more detailed description of the ohTopology software can be found [[Av:Developer:ohTopologyDescription | here]].&lt;br /&gt;
&lt;br /&gt;
= Streaming Services =&lt;br /&gt;
Both Linn's DS  and [[OhMediaPlayer | ohMediaPlayer]] include reference implementations for the following streaming services:&lt;br /&gt;
* [[TidalStreamingService | Tidal]]&lt;br /&gt;
* [[QobuzStreamingService | Qobuz]]&lt;br /&gt;
* [[CalmRadioInternetRadio | Calm Radio]]&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Scd</id>
		<title>Av:Developer:Scd</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Scd"/>
				<updated>2017-06-23T14:13:29Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Sample Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Songcast Direct =&lt;br /&gt;
== Overview ==&lt;br /&gt;
Songcast Direct (SCD) can be used to send decoded audio from any computing device to an OpenHome device.  The Sender device is responsible for decoding audio to PCM, framing this in a simple protocol and making it available via a simple TCP server.  The Receiver pulls data from this server, giving the Receiver complete control of the audio clock.&lt;br /&gt;
&lt;br /&gt;
A Songcast Direct sender performs a broadly similar role to a Songcast sender.  Applications that perform their own decoding to PCM will find SCD is easier to integrate and offers higher audio performance:&lt;br /&gt;
* There is a constant TCP connection between sender and receiver, avoiding the need for application-level resend support&lt;br /&gt;
* It uses the clock of the receiver, allowing for higher quality playback if the sender is on a desktop computer&lt;br /&gt;
* It offers the receiver limited control over the stream – initially seeking within a track or skipping between tracks.  While the primary control UI may reside on the sender device, this allows for integration with any Ir handset for the receiver.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
[https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd ohPipeline] contains sample code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;WavSender&amp;lt;/tt&amp;gt; contains an example of a trivial SCD Sender, scanning a single directory and decoding then sending any WAV files it finds. (Note that compilation of this is currently disabled.  &amp;lt;tt&amp;gt;DirScanner::Run()&amp;lt;/tt&amp;gt; contains code from an experimental precursor to C++17's &amp;lt;tt&amp;gt;std::filesystem::directory_iterator&amp;lt;/tt&amp;gt;.  Current code is compatible with VS2013; it should only require a couple of lines of change to make this compile against any more recent compiler.)&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd Scd] and [https://github.com/openhome/ohPipeline/tree/master/OpenHome/Av/Scd/Sender Sender] directories should be usable without any change.  It will be possible to write a commercial quality sender using the &amp;lt;tt&amp;gt;ScdSender&amp;lt;/tt&amp;gt; library, passing audio into &amp;lt;tt&amp;gt;IScdSupply&amp;lt;/tt&amp;gt; and relying on the configuration of &amp;lt;tt&amp;gt;ScdMsgFactory&amp;lt;/tt&amp;gt; to determine how much audio is buffered by the Sender.&lt;br /&gt;
&lt;br /&gt;
Sample code demonstrating how a Sender can control a Receiver via ODP is coming soon.  For now, see [https://github.com/openhome/ohPipeline/blob/master/OpenHome/Net/Odp/Tests/TestDvOdp.cpp ODP tests] for a basic example.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
=== SSDP ===&lt;br /&gt;
First search for &amp;lt;tt&amp;gt;av-openhome-org:service:Product:2&amp;lt;/tt&amp;gt; then either&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Attributes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;Transport&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Transport&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;SourceXml&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; for a source with &amp;lt;tt&amp;gt;Type&amp;lt;/tt&amp;gt; of &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== mDNS ===&lt;br /&gt;
Search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; service to identify ODP endpoint&lt;br /&gt;
&lt;br /&gt;
== Control ==&lt;br /&gt;
Control of the Receiver is out of band, via the standard [[OhMediaDevelopers#Network_Services | OpenHome network APIs]].  These are available over UPnP or [[OhMediaDevelopers#ODP | ODP]] (a single connected socket).&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
The protocol used for communication between Sender and Receiver contains the following message types:&lt;br /&gt;
{|&lt;br /&gt;
! '''Type'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
! '''Sent by'''&lt;br /&gt;
|-&lt;br /&gt;
| Ready&lt;br /&gt;
| Signals availability and version support to other party&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataDidl &lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataOh&lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Format&lt;br /&gt;
| Format for the following audio. Must be sent before any audio.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Audio&lt;br /&gt;
| Decoded audio.  Can only be sent after a &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; message describing  its sample rate etc.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextDidl&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextOh&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Halt&lt;br /&gt;
| Indicates that a break in audio follows.  E.g. at the end of a track with no further tracks to be played, or when the Sender has paused.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Disconnect&lt;br /&gt;
| Indicates that the originator of the message is closing its SCD session. No further audio will be available. The message receiver should disconnect its socket.&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| Seek&lt;br /&gt;
| Indicates that the Receiver wants to jump to a different point in the current track.&amp;lt;br&amp;gt;Is only sent for tracks that the Sender has indicated support seeking.&lt;br /&gt;
| Receiver&lt;br /&gt;
|-&lt;br /&gt;
| Skip&lt;br /&gt;
| Indicates that the Receiver wants to immediately jump to the next or previous track.&lt;br /&gt;
| Receiver&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A SCD session is initiated by the Sender.  It instantiates a simple TCP server then instructs the Receiver to start playing from it.&lt;br /&gt;
&lt;br /&gt;
The Receiver connects to the Sender and sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, indicating the protocol version it supports.  If the Sender is compatible with this version, it responds with a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the same version.  Otherwise, the Sender sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the version it supports.  If the Receiver cannot support this version, it must close the connection.&lt;br /&gt;
&lt;br /&gt;
After sending a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, the Sender should send either &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; (if it has nothing to send yet) or one of &amp;lt;tt&amp;gt;MetadataDidl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;MetadataOh&amp;lt;/tt&amp;gt; plus &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt;.  The order of &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; versus &amp;lt;tt&amp;gt;Metadata*&amp;lt;/tt&amp;gt; is not important.&lt;br /&gt;
&lt;br /&gt;
After this, the Sender should then send &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.  Any number of &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; messages can be sent until the end of the stream is reached.  &amp;lt;tt&amp;gt;Metatext&amp;lt;/tt&amp;gt; messages (either &amp;lt;tt&amp;gt;Didl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Oh&amp;lt;/tt&amp;gt;) may be interleaved with &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; message implies that a break in audio may follow.  If this break is during a stream, the Sender must have applied attenuation to samples immediately before this to avoid any audio artifacts at the break in transmission.  Senders which cannot do this should implement pausing of streams using the Transport.Pause control API instead.&lt;br /&gt;
&lt;br /&gt;
The details of the wire protocol are shown below.  Note that all multi-byte integer values are big endian.&lt;br /&gt;
{|&lt;br /&gt;
! '''Bytes'''&lt;br /&gt;
! '''Name'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| '''Header'''&lt;br /&gt;
|&lt;br /&gt;
| Prefixes to all messages below&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Signature&lt;br /&gt;
| 0x73, 0x63, 0x64,0x20 ('scd ')&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Type&lt;br /&gt;
| The type of message:&lt;br /&gt;
* 0 – Ready&lt;br /&gt;
* 1 – MetadataDidl&lt;br /&gt;
* 2 - MetaDataOh&lt;br /&gt;
* 3 – Format&lt;br /&gt;
* 5 – Audio&lt;br /&gt;
* 7 – MetatextDidl&lt;br /&gt;
* 8 – MetatextOh&lt;br /&gt;
* 9 – Halt&lt;br /&gt;
* 10 – Disconnect&lt;br /&gt;
* 11 – Seek&lt;br /&gt;
* 12 – Skip&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Length&lt;br /&gt;
| Length in bytes of the whole message including this header&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Reserved&lt;br /&gt;
| Unused, reserved for future use&lt;br /&gt;
|-&lt;br /&gt;
| '''Ready'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Major Version&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Minor Version&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| TrackUriLength&lt;br /&gt;
| Length, in bytes, of the track URI&lt;br /&gt;
|-&lt;br /&gt;
| m&lt;br /&gt;
| TrackUri&lt;br /&gt;
| The track URI, where m = TrackUriLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| MetadataLength&lt;br /&gt;
| Length, in bytes, of the track metadata, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metadata&lt;br /&gt;
| The track metadata, where n = MetadataLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metadata element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metadata element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metadata elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Format'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| BitDepth&lt;br /&gt;
| Bit depth of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| SampleRate&lt;br /&gt;
| Sample rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Channels&lt;br /&gt;
| Number of channels of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| BitRate&lt;br /&gt;
| Bit rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SamplesTotal&lt;br /&gt;
| Total number of samples in the following audio (requirement for this to be confirmed)&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SampleStart&lt;br /&gt;
| Sample position of the first sample in the next &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; message&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Flags&lt;br /&gt;
|&lt;br /&gt;
* Bit 0 - Seekable&lt;br /&gt;
* Bit 1 - Lossless&lt;br /&gt;
* Bit 2 - Live (content generated upstream of the Sender, e.g. internet radio)&lt;br /&gt;
* Bit 3 - Broadcastable (whether the Receiver is allowed to offer the following audio via any multi-room protocols&lt;br /&gt;
* Bits 4-7 - Reserved.  Must be zero.&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| CodecNameLength&lt;br /&gt;
| Length, in bytes, of the codec name&lt;br /&gt;
|-&lt;br /&gt;
| r&lt;br /&gt;
| CodecName&lt;br /&gt;
| The codec name, where r = CodecNameLength&lt;br /&gt;
|-&lt;br /&gt;
| '''Audio'''&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| NumSamples&lt;br /&gt;
| The number of audio samples in this message&lt;br /&gt;
|-&lt;br /&gt;
| s&lt;br /&gt;
| AudioData&lt;br /&gt;
| Audio data.  Where s = NumSamples * (BitDepth/8) * NumChannels.&amp;lt;br&amp;gt;Multi-channel audio must supply data sample at a time, with left channel first.  Audio is packed (i.e. no padding bytes rounding samples up to 32-bit boundaries) and big endian.&lt;br /&gt;
|-&lt;br /&gt;
| '''Metatextdidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Metatext Length&lt;br /&gt;
| Length, in bytes, of the metatext, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metatext&lt;br /&gt;
| The metatext, where n = MetatextLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metatext element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metatext element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metatext elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Halt'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Disconnect'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Seek'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|-&lt;br /&gt;
| '''Skip'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Scd</id>
		<title>Av:Developer:Scd</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Scd"/>
				<updated>2017-06-23T13:49:44Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* SSDP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Songcast Direct =&lt;br /&gt;
== Overview ==&lt;br /&gt;
Songcast Direct (SCD) can be used to send decoded audio from any computing device to an OpenHome device.  The Sender device is responsible for decoding audio to PCM, framing this in a simple protocol and making it available via a simple TCP server.  The Receiver pulls data from this server, giving the Receiver complete control of the audio clock.&lt;br /&gt;
&lt;br /&gt;
A Songcast Direct sender performs a broadly similar role to a Songcast sender.  Applications that perform their own decoding to PCM will find SCD is easier to integrate and offers higher audio performance:&lt;br /&gt;
* There is a constant TCP connection between sender and receiver, avoiding the need for application-level resend support&lt;br /&gt;
* It uses the clock of the receiver, allowing for higher quality playback if the sender is on a desktop computer&lt;br /&gt;
* It offers the receiver limited control over the stream – initially seeking within a track or skipping between tracks.  While the primary control UI may reside on the sender device, this allows for integration with any Ir handset for the receiver.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
Sample code exists for all key aspects of the Sender – server, framing and control.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
=== SSDP ===&lt;br /&gt;
First search for &amp;lt;tt&amp;gt;av-openhome-org:service:Product:2&amp;lt;/tt&amp;gt; then either&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Attributes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;Transport&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Transport&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;SourceXml&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; for a source with &amp;lt;tt&amp;gt;Type&amp;lt;/tt&amp;gt; of &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== mDNS ===&lt;br /&gt;
Search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; service to identify ODP endpoint&lt;br /&gt;
&lt;br /&gt;
== Control ==&lt;br /&gt;
Control of the Receiver is out of band, via the standard [[OhMediaDevelopers#Network_Services | OpenHome network APIs]].  These are available over UPnP or [[OhMediaDevelopers#ODP | ODP]] (a single connected socket).&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
The protocol used for communication between Sender and Receiver contains the following message types:&lt;br /&gt;
{|&lt;br /&gt;
! '''Type'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
! '''Sent by'''&lt;br /&gt;
|-&lt;br /&gt;
| Ready&lt;br /&gt;
| Signals availability and version support to other party&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataDidl &lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataOh&lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Format&lt;br /&gt;
| Format for the following audio. Must be sent before any audio.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Audio&lt;br /&gt;
| Decoded audio.  Can only be sent after a &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; message describing  its sample rate etc.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextDidl&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextOh&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Halt&lt;br /&gt;
| Indicates that a break in audio follows.  E.g. at the end of a track with no further tracks to be played, or when the Sender has paused.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Disconnect&lt;br /&gt;
| Indicates that the originator of the message is closing its SCD session. No further audio will be available. The message receiver should disconnect its socket.&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| Seek&lt;br /&gt;
| Indicates that the Receiver wants to jump to a different point in the current track.&amp;lt;br&amp;gt;Is only sent for tracks that the Sender has indicated support seeking.&lt;br /&gt;
| Receiver&lt;br /&gt;
|-&lt;br /&gt;
| Skip&lt;br /&gt;
| Indicates that the Receiver wants to immediately jump to the next or previous track.&lt;br /&gt;
| Receiver&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A SCD session is initiated by the Sender.  It instantiates a simple TCP server then instructs the Receiver to start playing from it.&lt;br /&gt;
&lt;br /&gt;
The Receiver connects to the Sender and sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, indicating the protocol version it supports.  If the Sender is compatible with this version, it responds with a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the same version.  Otherwise, the Sender sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the version it supports.  If the Receiver cannot support this version, it must close the connection.&lt;br /&gt;
&lt;br /&gt;
After sending a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, the Sender should send either &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; (if it has nothing to send yet) or one of &amp;lt;tt&amp;gt;MetadataDidl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;MetadataOh&amp;lt;/tt&amp;gt; plus &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt;.  The order of &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; versus &amp;lt;tt&amp;gt;Metadata*&amp;lt;/tt&amp;gt; is not important.&lt;br /&gt;
&lt;br /&gt;
After this, the Sender should then send &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.  Any number of &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; messages can be sent until the end of the stream is reached.  &amp;lt;tt&amp;gt;Metatext&amp;lt;/tt&amp;gt; messages (either &amp;lt;tt&amp;gt;Didl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Oh&amp;lt;/tt&amp;gt;) may be interleaved with &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; message implies that a break in audio may follow.  If this break is during a stream, the Sender must have applied attenuation to samples immediately before this to avoid any audio artifacts at the break in transmission.  Senders which cannot do this should implement pausing of streams using the Transport.Pause control API instead.&lt;br /&gt;
&lt;br /&gt;
The details of the wire protocol are shown below.  Note that all multi-byte integer values are big endian.&lt;br /&gt;
{|&lt;br /&gt;
! '''Bytes'''&lt;br /&gt;
! '''Name'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| '''Header'''&lt;br /&gt;
|&lt;br /&gt;
| Prefixes to all messages below&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Signature&lt;br /&gt;
| 0x73, 0x63, 0x64,0x20 ('scd ')&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Type&lt;br /&gt;
| The type of message:&lt;br /&gt;
* 0 – Ready&lt;br /&gt;
* 1 – MetadataDidl&lt;br /&gt;
* 2 - MetaDataOh&lt;br /&gt;
* 3 – Format&lt;br /&gt;
* 5 – Audio&lt;br /&gt;
* 7 – MetatextDidl&lt;br /&gt;
* 8 – MetatextOh&lt;br /&gt;
* 9 – Halt&lt;br /&gt;
* 10 – Disconnect&lt;br /&gt;
* 11 – Seek&lt;br /&gt;
* 12 – Skip&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Length&lt;br /&gt;
| Length in bytes of the whole message including this header&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Reserved&lt;br /&gt;
| Unused, reserved for future use&lt;br /&gt;
|-&lt;br /&gt;
| '''Ready'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Major Version&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Minor Version&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| TrackUriLength&lt;br /&gt;
| Length, in bytes, of the track URI&lt;br /&gt;
|-&lt;br /&gt;
| m&lt;br /&gt;
| TrackUri&lt;br /&gt;
| The track URI, where m = TrackUriLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| MetadataLength&lt;br /&gt;
| Length, in bytes, of the track metadata, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metadata&lt;br /&gt;
| The track metadata, where n = MetadataLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metadata element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metadata element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metadata elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Format'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| BitDepth&lt;br /&gt;
| Bit depth of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| SampleRate&lt;br /&gt;
| Sample rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Channels&lt;br /&gt;
| Number of channels of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| BitRate&lt;br /&gt;
| Bit rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SamplesTotal&lt;br /&gt;
| Total number of samples in the following audio (requirement for this to be confirmed)&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SampleStart&lt;br /&gt;
| Sample position of the first sample in the next &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; message&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Flags&lt;br /&gt;
|&lt;br /&gt;
* Bit 0 - Seekable&lt;br /&gt;
* Bit 1 - Lossless&lt;br /&gt;
* Bit 2 - Live (content generated upstream of the Sender, e.g. internet radio)&lt;br /&gt;
* Bit 3 - Broadcastable (whether the Receiver is allowed to offer the following audio via any multi-room protocols&lt;br /&gt;
* Bits 4-7 - Reserved.  Must be zero.&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| CodecNameLength&lt;br /&gt;
| Length, in bytes, of the codec name&lt;br /&gt;
|-&lt;br /&gt;
| r&lt;br /&gt;
| CodecName&lt;br /&gt;
| The codec name, where r = CodecNameLength&lt;br /&gt;
|-&lt;br /&gt;
| '''Audio'''&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| NumSamples&lt;br /&gt;
| The number of audio samples in this message&lt;br /&gt;
|-&lt;br /&gt;
| s&lt;br /&gt;
| AudioData&lt;br /&gt;
| Audio data.  Where s = NumSamples * (BitDepth/8) * NumChannels.&amp;lt;br&amp;gt;Multi-channel audio must supply data sample at a time, with left channel first.  Audio is packed (i.e. no padding bytes rounding samples up to 32-bit boundaries) and big endian.&lt;br /&gt;
|-&lt;br /&gt;
| '''Metatextdidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Metatext Length&lt;br /&gt;
| Length, in bytes, of the metatext, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metatext&lt;br /&gt;
| The metatext, where n = MetatextLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metatext element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metatext element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metatext elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Halt'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Disconnect'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Seek'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|-&lt;br /&gt;
| '''Skip'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Scd</id>
		<title>Av:Developer:Scd</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Scd"/>
				<updated>2017-06-23T13:48:21Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Songcast Direct =&lt;br /&gt;
== Overview ==&lt;br /&gt;
Songcast Direct (SCD) can be used to send decoded audio from any computing device to an OpenHome device.  The Sender device is responsible for decoding audio to PCM, framing this in a simple protocol and making it available via a simple TCP server.  The Receiver pulls data from this server, giving the Receiver complete control of the audio clock.&lt;br /&gt;
&lt;br /&gt;
A Songcast Direct sender performs a broadly similar role to a Songcast sender.  Applications that perform their own decoding to PCM will find SCD is easier to integrate and offers higher audio performance:&lt;br /&gt;
* There is a constant TCP connection between sender and receiver, avoiding the need for application-level resend support&lt;br /&gt;
* It uses the clock of the receiver, allowing for higher quality playback if the sender is on a desktop computer&lt;br /&gt;
* It offers the receiver limited control over the stream – initially seeking within a track or skipping between tracks.  While the primary control UI may reside on the sender device, this allows for integration with any Ir handset for the receiver.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
Sample code exists for all key aspects of the Sender – server, framing and control.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
=== SSDP ===&lt;br /&gt;
First search for &amp;lt;tt&amp;gt;av-openhome-org:service:Product:2&amp;lt;/tt&amp;gt; then either&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Attributes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;Transport&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Transport&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
=== mDNS ===&lt;br /&gt;
Search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; service to identify ODP endpoint&lt;br /&gt;
&lt;br /&gt;
== Control ==&lt;br /&gt;
Control of the Receiver is out of band, via the standard [[OhMediaDevelopers#Network_Services | OpenHome network APIs]].  These are available over UPnP or [[OhMediaDevelopers#ODP | ODP]] (a single connected socket).&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
The protocol used for communication between Sender and Receiver contains the following message types:&lt;br /&gt;
{|&lt;br /&gt;
! '''Type'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
! '''Sent by'''&lt;br /&gt;
|-&lt;br /&gt;
| Ready&lt;br /&gt;
| Signals availability and version support to other party&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataDidl &lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataOh&lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Format&lt;br /&gt;
| Format for the following audio. Must be sent before any audio.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Audio&lt;br /&gt;
| Decoded audio.  Can only be sent after a &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; message describing  its sample rate etc.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextDidl&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextOh&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Halt&lt;br /&gt;
| Indicates that a break in audio follows.  E.g. at the end of a track with no further tracks to be played, or when the Sender has paused.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Disconnect&lt;br /&gt;
| Indicates that the originator of the message is closing its SCD session. No further audio will be available. The message receiver should disconnect its socket.&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| Seek&lt;br /&gt;
| Indicates that the Receiver wants to jump to a different point in the current track.&amp;lt;br&amp;gt;Is only sent for tracks that the Sender has indicated support seeking.&lt;br /&gt;
| Receiver&lt;br /&gt;
|-&lt;br /&gt;
| Skip&lt;br /&gt;
| Indicates that the Receiver wants to immediately jump to the next or previous track.&lt;br /&gt;
| Receiver&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A SCD session is initiated by the Sender.  It instantiates a simple TCP server then instructs the Receiver to start playing from it.&lt;br /&gt;
&lt;br /&gt;
The Receiver connects to the Sender and sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, indicating the protocol version it supports.  If the Sender is compatible with this version, it responds with a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the same version.  Otherwise, the Sender sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the version it supports.  If the Receiver cannot support this version, it must close the connection.&lt;br /&gt;
&lt;br /&gt;
After sending a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, the Sender should send either &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; (if it has nothing to send yet) or one of &amp;lt;tt&amp;gt;MetadataDidl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;MetadataOh&amp;lt;/tt&amp;gt; plus &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt;.  The order of &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; versus &amp;lt;tt&amp;gt;Metadata*&amp;lt;/tt&amp;gt; is not important.&lt;br /&gt;
&lt;br /&gt;
After this, the Sender should then send &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.  Any number of &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; messages can be sent until the end of the stream is reached.  &amp;lt;tt&amp;gt;Metatext&amp;lt;/tt&amp;gt; messages (either &amp;lt;tt&amp;gt;Didl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Oh&amp;lt;/tt&amp;gt;) may be interleaved with &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; message implies that a break in audio may follow.  If this break is during a stream, the Sender must have applied attenuation to samples immediately before this to avoid any audio artifacts at the break in transmission.  Senders which cannot do this should implement pausing of streams using the Transport.Pause control API instead.&lt;br /&gt;
&lt;br /&gt;
The details of the wire protocol are shown below.  Note that all multi-byte integer values are big endian.&lt;br /&gt;
{|&lt;br /&gt;
! '''Bytes'''&lt;br /&gt;
! '''Name'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| '''Header'''&lt;br /&gt;
|&lt;br /&gt;
| Prefixes to all messages below&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Signature&lt;br /&gt;
| 0x73, 0x63, 0x64,0x20 ('scd ')&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Type&lt;br /&gt;
| The type of message:&lt;br /&gt;
* 0 – Ready&lt;br /&gt;
* 1 – MetadataDidl&lt;br /&gt;
* 2 - MetaDataOh&lt;br /&gt;
* 3 – Format&lt;br /&gt;
* 5 – Audio&lt;br /&gt;
* 7 – MetatextDidl&lt;br /&gt;
* 8 – MetatextOh&lt;br /&gt;
* 9 – Halt&lt;br /&gt;
* 10 – Disconnect&lt;br /&gt;
* 11 – Seek&lt;br /&gt;
* 12 – Skip&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Length&lt;br /&gt;
| Length in bytes of the whole message including this header&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Reserved&lt;br /&gt;
| Unused, reserved for future use&lt;br /&gt;
|-&lt;br /&gt;
| '''Ready'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Major Version&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Minor Version&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| TrackUriLength&lt;br /&gt;
| Length, in bytes, of the track URI&lt;br /&gt;
|-&lt;br /&gt;
| m&lt;br /&gt;
| TrackUri&lt;br /&gt;
| The track URI, where m = TrackUriLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| MetadataLength&lt;br /&gt;
| Length, in bytes, of the track metadata, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metadata&lt;br /&gt;
| The track metadata, where n = MetadataLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metadata element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metadata element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metadata elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Format'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| BitDepth&lt;br /&gt;
| Bit depth of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| SampleRate&lt;br /&gt;
| Sample rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Channels&lt;br /&gt;
| Number of channels of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| BitRate&lt;br /&gt;
| Bit rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SamplesTotal&lt;br /&gt;
| Total number of samples in the following audio (requirement for this to be confirmed)&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SampleStart&lt;br /&gt;
| Sample position of the first sample in the next &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; message&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Flags&lt;br /&gt;
|&lt;br /&gt;
* Bit 0 - Seekable&lt;br /&gt;
* Bit 1 - Lossless&lt;br /&gt;
* Bit 2 - Live (content generated upstream of the Sender, e.g. internet radio)&lt;br /&gt;
* Bit 3 - Broadcastable (whether the Receiver is allowed to offer the following audio via any multi-room protocols&lt;br /&gt;
* Bits 4-7 - Reserved.  Must be zero.&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| CodecNameLength&lt;br /&gt;
| Length, in bytes, of the codec name&lt;br /&gt;
|-&lt;br /&gt;
| r&lt;br /&gt;
| CodecName&lt;br /&gt;
| The codec name, where r = CodecNameLength&lt;br /&gt;
|-&lt;br /&gt;
| '''Audio'''&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| NumSamples&lt;br /&gt;
| The number of audio samples in this message&lt;br /&gt;
|-&lt;br /&gt;
| s&lt;br /&gt;
| AudioData&lt;br /&gt;
| Audio data.  Where s = NumSamples * (BitDepth/8) * NumChannels.&amp;lt;br&amp;gt;Multi-channel audio must supply data sample at a time, with left channel first.  Audio is packed (i.e. no padding bytes rounding samples up to 32-bit boundaries) and big endian.&lt;br /&gt;
|-&lt;br /&gt;
| '''Metatextdidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Metatext Length&lt;br /&gt;
| Length, in bytes, of the metatext, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metatext&lt;br /&gt;
| The metatext, where n = MetatextLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metatext element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metatext element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metatext elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Halt'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Disconnect'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Seek'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|-&lt;br /&gt;
| '''Skip'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Scd</id>
		<title>Av:Developer:Scd</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Scd"/>
				<updated>2017-06-23T13:47:07Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Add wire protocol&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Songcast Direct =&lt;br /&gt;
== Overview ==&lt;br /&gt;
Songcast Direct (SCD) can be used to send decoded audio from any computing device to an OpenHome device.  The Sender device is responsible for decoding audio to PCM, framing this in a simple protocol and making it available via a simple TCP server.  The Receiver pulls data from this server, giving the Receiver complete control of the audio clock.&lt;br /&gt;
&lt;br /&gt;
A Songcast Direct sender performs a broadly similar role to a Songcast sender.  Applications that perform their own decoding to PCM will find SCD is easier to integrate and offers higher audio performance:&lt;br /&gt;
* There is a constant TCP connection between sender and receiver, avoiding the need for application-level resend support&lt;br /&gt;
* It uses the clock of the receiver, allowing for higher quality playback if the sender is on a desktop computer&lt;br /&gt;
* It offers the receiver limited control over the stream – initially seeking within a track or skipping between tracks.  While the primary control UI may reside on the sender device, this allows for integration with any Ir handset for the receiver.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
Sample code exists for all key aspects of the Sender – server, framing and control.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
=== SSDP ===&lt;br /&gt;
First search for &amp;lt;tt&amp;gt;av-openhome-org:service:Product:2&amp;lt;/tt&amp;gt; then either&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Attributes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;Transport&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Transport&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
=== mDNS ===&lt;br /&gt;
Search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; service to identify ODP endpoint&lt;br /&gt;
&lt;br /&gt;
== Control ==&lt;br /&gt;
Control of the Receiver is out of band, via the standard [[OhMediaDevelopers#Network_Services | OpenHome network APIs]].  These are available over UPnP or [[OhMediaDevelopers#ODP | ODP]] (a single connected socket).&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
The protocol used for communication between Sender and Receiver contains the following message types:&lt;br /&gt;
{|&lt;br /&gt;
! '''Type'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
! '''Sent by'''&lt;br /&gt;
|-&lt;br /&gt;
| Ready&lt;br /&gt;
| Signals availability and version support to other party&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataDidl &lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataOh&lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Format&lt;br /&gt;
| Format for the following audio. Must be sent before any audio.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Audio&lt;br /&gt;
| Decoded audio.  Can only be sent after a &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; message describing  its sample rate etc.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextDidl&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextOh&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Halt&lt;br /&gt;
| Indicates that a break in audio follows.  E.g. at the end of a track with no further tracks to be played, or when the Sender has paused.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Disconnect&lt;br /&gt;
| Indicates that the originator of the message is closing its SCD session. No further audio will be available. The message receiver should disconnect its socket.&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| Seek&lt;br /&gt;
| Indicates that the Receiver wants to jump to a different point in the current track.&amp;lt;br&amp;gt;Is only sent for tracks that the Sender has indicated support seeking.&lt;br /&gt;
| Receiver&lt;br /&gt;
|-&lt;br /&gt;
| Skip&lt;br /&gt;
| Indicates that the Receiver wants to immediately jump to the next or previous track.&lt;br /&gt;
| Receiver&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A SCD session is initiated by the Sender.  It instantiates a simple TCP server then instructs the Receiver to start playing from it.&lt;br /&gt;
&lt;br /&gt;
The Receiver connects to the Sender and sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, indicating the protocol version it supports.  If the Sender is compatible with this version, it responds with a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the same version.  Otherwise, the Sender sends a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message stating the version it supports.  If the Receiver cannot support this version, it must close the connection.&lt;br /&gt;
&lt;br /&gt;
After sending a &amp;lt;tt&amp;gt;Ready&amp;lt;/tt&amp;gt; message, the Sender should send either &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; (if it has nothing to send yet) or one of &amp;lt;tt&amp;gt;MetadataDidl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;MetadataOh&amp;lt;/tt&amp;gt; plus &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt;.  The order of &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; versus &amp;lt;tt&amp;gt;Metadata*&amp;lt;/tt&amp;gt; is not important.&lt;br /&gt;
&lt;br /&gt;
After this, the Sender should then send &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.  Any number of &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; messages can be sent until the end of the stream is reached.  &amp;lt;tt&amp;gt;Metatext&amp;lt;/tt&amp;gt; messages (either &amp;lt;tt&amp;gt;Didl&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Oh&amp;lt;/tt&amp;gt;) may be interleaved with &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;tt&amp;gt;Halt&amp;lt;/tt&amp;gt; message implies that a break in audio may follow.  If this break is during a stream, the Sender must have applied attenuation to samples immediately before this to avoid any audio artifacts at the break in transmission.  Senders which cannot do this should implement pausing of streams using the Transport.Pause control API instead.&lt;br /&gt;
&lt;br /&gt;
The details of the wire protocol are shown below.  Note that all multi-byte integer values are big endian.&lt;br /&gt;
{|&lt;br /&gt;
! '''Bytes'''&lt;br /&gt;
! '''Name'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| '''Header (all messages)'''&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Signature&lt;br /&gt;
| 0x73, 0x63, 0x64,0x20 ('scd ')&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Type&lt;br /&gt;
| The type of message:&lt;br /&gt;
* 0 – Ready&lt;br /&gt;
* 1 – MetadataDidl&lt;br /&gt;
* 2 - MetaDataOh&lt;br /&gt;
* 3 – Format&lt;br /&gt;
* 5 – Audio&lt;br /&gt;
* 7 – MetatextDidl&lt;br /&gt;
* 8 – MetatextOh&lt;br /&gt;
* 9 – Halt&lt;br /&gt;
* 10 – Disconnect&lt;br /&gt;
* 11 – Seek&lt;br /&gt;
* 12 – Skip&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Length&lt;br /&gt;
| Length in bytes of the whole message including this header&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Reserved&lt;br /&gt;
| Unused, reserved for future use&lt;br /&gt;
|-&lt;br /&gt;
| '''Ready'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Major Version&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Minor Version&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataDidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| TrackUriLength&lt;br /&gt;
| Length, in bytes, of the track URI&lt;br /&gt;
|-&lt;br /&gt;
| m&lt;br /&gt;
| TrackUri&lt;br /&gt;
| The track URI, where m = TrackUriLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| MetadataLength&lt;br /&gt;
| Length, in bytes, of the track metadata, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metadata&lt;br /&gt;
| The track metadata, where n = MetadataLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetadataOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metadata element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metadata element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metadata elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Format'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| BitDepth&lt;br /&gt;
| Bit depth of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| SampleRate&lt;br /&gt;
| Sample rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Channels&lt;br /&gt;
| Number of channels of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| BitRate&lt;br /&gt;
| Bit rate of the following audio&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SamplesTotal&lt;br /&gt;
| Total number of samples in the following audio (requirement for this to be confirmed)&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| SampleStart&lt;br /&gt;
| Sample position of the first sample in the next &amp;lt;tt&amp;gt;Audio&amp;lt;/tt&amp;gt; message&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Flags&lt;br /&gt;
|&lt;br /&gt;
* Bit 0 - Seekable&lt;br /&gt;
* Bit 1 - Lossless&lt;br /&gt;
* Bit 2 - Live (content generated upstream of the Sender, e.g. internet radio)&lt;br /&gt;
* Bit 3 - Broadcastable (whether the Receiver is allowed to offer the following audio via any multi-room protocols&lt;br /&gt;
* Bits 4-7 - Reserved.  Must be zero.&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| CodecNameLength&lt;br /&gt;
| Length, in bytes, of the codec name&lt;br /&gt;
|-&lt;br /&gt;
| r&lt;br /&gt;
| CodecName&lt;br /&gt;
| The codec name, where r = CodecNameLength&lt;br /&gt;
|-&lt;br /&gt;
| '''Audio'''&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| NumSamples&lt;br /&gt;
| The number of audio samples in this message&lt;br /&gt;
|-&lt;br /&gt;
| s&lt;br /&gt;
| AudioData&lt;br /&gt;
| Audio data.  Where s = NumSamples * (BitDepth/8) * NumChannels.&amp;lt;br&amp;gt;Multi-channel audio must supply data sample at a time, with left channel first.  Audio is packed (i.e. no padding bytes rounding samples up to 32-bit boundaries) and big endian.&lt;br /&gt;
|-&lt;br /&gt;
| '''Metatextdidl'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Metatext Length&lt;br /&gt;
| Length, in bytes, of the metatext, in DIDL-Lite format&lt;br /&gt;
|-&lt;br /&gt;
| n&lt;br /&gt;
| Metatext&lt;br /&gt;
| The metatext, where n = MetatextLength&lt;br /&gt;
|-&lt;br /&gt;
| '''MetatextOh'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Count&lt;br /&gt;
| Number of key-value pairs that follow&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| KeyLength&lt;br /&gt;
| Length, in bytes, of the key&lt;br /&gt;
|-&lt;br /&gt;
| p&lt;br /&gt;
| Key&lt;br /&gt;
| Key for the metatext element, where p = KeyLength&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| ValueLength&lt;br /&gt;
| Length, in bytes, of the value&lt;br /&gt;
|-&lt;br /&gt;
| q&lt;br /&gt;
| Value&lt;br /&gt;
| Value for the metatext element, where q = ValueLength&lt;br /&gt;
|-&lt;br /&gt;
| ...&lt;br /&gt;
| ...&lt;br /&gt;
| Repeat key-value pairs for all Count metatext elements&lt;br /&gt;
|-&lt;br /&gt;
| '''Halt'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Disconnect'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| No message body (only header required)&lt;br /&gt;
|-&lt;br /&gt;
| '''Seek'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|-&lt;br /&gt;
| '''Skip'''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| To be confirmed &lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Av:Developer:Scd</id>
		<title>Av:Developer:Scd</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Av:Developer:Scd"/>
				<updated>2017-06-23T12:47:35Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: Created page with &amp;quot;= Songcast Direct = == Overview == Songcast Direct (SCD) can be used to send decoded audio from any computing device to an OpenHome device.  The Sender device is responsible for ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Songcast Direct =&lt;br /&gt;
== Overview ==&lt;br /&gt;
Songcast Direct (SCD) can be used to send decoded audio from any computing device to an OpenHome device.  The Sender device is responsible for decoding audio to PCM, framing this in a simple protocol and making it available via a simple TCP server.  The Receiver pulls data from this server, giving the Receiver complete control of the audio clock.&lt;br /&gt;
&lt;br /&gt;
A Songcast Direct sender performs a broadly similar role to a Songcast sender.  Applications that perform their own decoding to PCM will find SCD is easier to integrate and offers higher audio performance:&lt;br /&gt;
* There is a constant TCP connection between sender and receiver, avoiding the need for application-level resend support&lt;br /&gt;
* It uses the clock of the receiver, allowing for higher quality playback if the sender is on a desktop computer&lt;br /&gt;
* It offers the receiver limited control over the stream – initially seeking within a track or skipping between tracks.  While the primary control UI may reside on the sender device, this allows for integration with any Ir handset for the receiver.&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
Sample code exists for all key aspects of the Sender – server, framing and control.&lt;br /&gt;
&lt;br /&gt;
== Discovery ==&lt;br /&gt;
=== SSDP ===&lt;br /&gt;
First search for &amp;lt;tt&amp;gt;av-openhome-org:service:Product:2&amp;lt;/tt&amp;gt; then either&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Attributes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Product&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;Transport&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Check &amp;lt;tt&amp;gt;Modes&amp;lt;/tt&amp;gt; on &amp;lt;tt&amp;gt;Transport&amp;lt;/tt&amp;gt; service for &amp;lt;tt&amp;gt;&amp;quot;scd&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
=== mDNS ===&lt;br /&gt;
Search for &amp;lt;tt&amp;gt;_openhome._odp&amp;lt;/tt&amp;gt; service to identify ODP endpoint&lt;br /&gt;
&lt;br /&gt;
== Control ==&lt;br /&gt;
Control of the Receiver is out of band, via the standard [[OhMediaDevelopers#Network_Services | OpenHome network APIs]].  These are available over UPnP or [[OhMediaDevelopers#ODP | ODP]] (a single connected socket).&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
The protocol used for communication between Sender and Receiver contains the following message types:&lt;br /&gt;
{|&lt;br /&gt;
! '''Type'''&lt;br /&gt;
! '''Description'''&lt;br /&gt;
! '''Sent by'''&lt;br /&gt;
|-&lt;br /&gt;
| Ready&lt;br /&gt;
| Signals availability and version support to other party&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataDidl &lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetadataOh&lt;br /&gt;
| Metadata relevant until the end of the next track.&amp;lt;br&amp;gt;Will cause the receiver to reset its reported time indicator for the audio stream.&amp;lt;br&amp;gt;Should be sent after all Audio for any preceding track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Format&lt;br /&gt;
| Format for the following audio. Must be sent before any audio.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Audio&lt;br /&gt;
| Decoded audio.  Can only be sent after a &amp;lt;tt&amp;gt;Format&amp;lt;/tt&amp;gt; message describing  its sample rate etc.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextDidl&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses DIDL-Lite.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| MetatextOh&lt;br /&gt;
| Metadata relevant to a portion of a track.&amp;lt;br&amp;gt;May be sent [0..n] times during a track.&amp;lt;br&amp;gt;Uses [[Av::OhMetadata | OpenHome Metadata format]].&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Halt&lt;br /&gt;
| Indicates that a break in audio follows.  E.g. at the end of a track with no further tracks to be played, or when the Sender has paused.&lt;br /&gt;
| Sender&lt;br /&gt;
|-&lt;br /&gt;
| Disconnect&lt;br /&gt;
| Indicates that the originator of the message is closing its SCD session. No further audio will be available. The message receiver should disconnect its socket.&lt;br /&gt;
| Receiver &amp;amp; Sender&lt;br /&gt;
|-&lt;br /&gt;
| Seek&lt;br /&gt;
| Indicates that the Receiver wants to jump to a different point in the current track.&amp;lt;br&amp;gt;Is only sent for tracks that the Sender has indicated support seeking.&lt;br /&gt;
| Receiver&lt;br /&gt;
|-&lt;br /&gt;
| Skip&lt;br /&gt;
| Indicates that the Receiver wants to immediately jump to the next or previous track.&lt;br /&gt;
| Receiver&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhMediaDevelopers</id>
		<title>OhMediaDevelopers</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhMediaDevelopers"/>
				<updated>2017-06-23T11:37:19Z</updated>
		
		<summary type="html">&lt;p&gt;Simonc: /* Direct */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Network Services =&lt;br /&gt;
ohMedia defines the following network services:&lt;br /&gt;
* [[Av:Developer:ProductService | Product]].  The core of a renderer and the only mandatory service.  The state of this service allows control points to infer which other services are present on a device.  In more complex installations it allows devices to mapped into a multi-room hi-fi system&lt;br /&gt;
* [[Av:Developer:PlaylistService | Playlist]].  An ordered list of tracks to be played.&lt;br /&gt;
* [[Av:Developer:RadioService | Radio]].  Browse and select from a list of favourite internet radio, podcast and listen again presets.&lt;br /&gt;
* [[Av:Developer:InfoService | Info]].  Report information about currently playing track.&lt;br /&gt;
* [[Av:Developer:TimeService | Time]].  Report information about progress through a track.&lt;br /&gt;
* [[Av:Developer:VolumeService | Volume]].  Control volume on a renderer or a connected pre-amp.&lt;br /&gt;
* [[Av:Developer:TransportService | Transport]].  Source-independent transport controls.&lt;br /&gt;
* [[Av:Developer:SenderService | Sender]].  Indicate presence and state of a Songcast sender.&lt;br /&gt;
* [[Av:Developer:ReceiverService | Receiver]].  Control a Songcast receiver.&lt;br /&gt;
* [[Av:Developer:CredentialsService | Credentials]].  Securely manage login details for external services supported by a device.&lt;br /&gt;
* NetworkMonitor.  Measures network performance.&lt;br /&gt;
* [[Av:Developer:PlaylistManagerService | PlaylistManager]].  Included in media servers.  Allows playlists to be shared between renderers and saved for future reuse.&lt;br /&gt;
&lt;br /&gt;
The [[Av:Developer:EriskayServices | Eriskay]] family of services will later replace these.  Feedback on Eriskay is welcomed.&lt;br /&gt;
&lt;br /&gt;
= UPnP =&lt;br /&gt;
All ohMedia products publish and/or consume network services using UPnP.  This is enabled by [[OhNet | ohNet]] - a cross-platform UPnP stack suitable for use in control points and devices.  ohNet is open source, liberally licensed and intended for use in external products.&lt;br /&gt;
&lt;br /&gt;
= Songcast =&lt;br /&gt;
The Songcast brand encompasses a range of products and protocols.&lt;br /&gt;
&lt;br /&gt;
== Desktop senders ==&lt;br /&gt;
Virtual audio drivers that send all audio from a Windows or Mac device to a songcast receiver.  [https://www.linn.co.uk/software#songcast Linn] provide a full implementation of these.  The bulk of the code required is also available in the [https://github.com/openhome/ohSongcast ohSongcast] repo.&lt;br /&gt;
&lt;br /&gt;
== Multi-room ==&lt;br /&gt;
The Songcast protocol enables synchronised playing of audio from an unbounded number of ohMedia renderers.&lt;br /&gt;
&lt;br /&gt;
The [https://github.com/openhome/ohSongcast ohSongcast] repo provides a cross-platform C++ library offering much of the code needed to write a stand-alone songcast sender.  The [https://github.com/openhome/ohPipeline ohPipeline] repo contains a reference sender and receiver fully integrated to the OpenHome reference audio pipeline.&lt;br /&gt;
&lt;br /&gt;
The Songcast protocols are also documented:&lt;br /&gt;
* [[Av:Developer:Songcast:Ohm | OHM/OHU protocol specification]]&lt;br /&gt;
* [[Av:Developer:Songcast:Ohz | OHZ protocol specification]]&lt;br /&gt;
&lt;br /&gt;
== Direct ==&lt;br /&gt;
A specialised protocol used when there is a single receiver and the sender has control over the rate of streaming (this often means that the sender is responsible for audio decode).  More information, including protocol spec and sample code is available [[Av:Developer:Scd | here]].&lt;br /&gt;
&lt;br /&gt;
= Topology =&lt;br /&gt;
ohMedia models a home as a number of hi-fi systems, which are located in rooms.&lt;br /&gt;
&lt;br /&gt;
A hi-fi system is modelled as a hierarchical tree of products, where a product is defined as a single physical box that is located in a room, has a unique name within the room, has at least one output and any number of inputs.&lt;br /&gt;
&lt;br /&gt;
A product is modelled through the [[Av:Developer:ProductService | Product]] service specification.&lt;br /&gt;
&lt;br /&gt;
When a control point wants to construct a model of a user's home they use the Topology algorithm:&lt;br /&gt;
* discover all the products in the home that have a Product service&lt;br /&gt;
* group the discovered products based on the room they are in&lt;br /&gt;
* create a hierarchical tree structure by matching source names to product names *&lt;br /&gt;
* discover source functionality based on source type&lt;br /&gt;
* discover additional functionality based on product attributes&lt;br /&gt;
Example implementations of the Topology algorithm are available in C# and C++ from the [https://github.com/openhome/ohTopology ohTopology] github repo.&lt;br /&gt;
&lt;br /&gt;
A more detailed description of the ohTopology software can be found [[Av:Developer:ohTopologyDescription | here]].&lt;br /&gt;
&lt;br /&gt;
= Streaming Services =&lt;br /&gt;
Both Linn's DS  and [[OhMediaPlayer | ohMediaPlayer]] include reference implementations for the following streaming services:&lt;br /&gt;
* [[TidalStreamingService | Tidal]]&lt;br /&gt;
* [[QobuzStreamingService | Qobuz]]&lt;br /&gt;
* [[CalmRadioInternetRadio | Calm Radio]]&lt;/div&gt;</summary>
		<author><name>Simonc</name></author>	</entry>

	</feed>