


{"id":11074,"date":"2017-09-08T22:11:18","date_gmt":"2017-09-08T22:11:18","guid":{"rendered":"https:\/\/expressplay.local\/?page_id=11074"},"modified":"2021-02-10T12:00:55","modified_gmt":"2021-02-10T20:00:55","slug":"sdk-overview-source","status":"publish","type":"page","link":"https:\/\/www.expressplay.com\/ko\/developer\/sdk-overview-source\/","title":{"rendered":"Source SDK Development Guide"},"content":{"rendered":"<style>\nh2,h3,table {\n    margin: 20px 0;\n}<\/p>\n<p>table td, table th {\n    padding: 15px;\n}\ncode {\n    word-break: break-all;\n    white-space: pre-wrap;\n    font-size: 14px;\n    color: #555;\n    margin: 20px 0;\n}<\/p>\n<\/style>\n<h2>Source SDK Development Guide<\/h2>\n<div class=\"bg-grey-100 p-8\" id=\"rest-api_my-sub-menu\">\n<p>Jump to section<\/p>\n<ol>\n<li><a href=\"#whatthesdkcando\" class=\"my-hyperlink\">What the SDK Can Do<\/a><\/li>\n<li><a href=\"#whatarethestepstoplay\" class=\"my-hyperlink\">What Are the Steps to Play<\/a><\/li>\n<li><a href=\"#whatarethestepsforebooks\" class=\"my-hyperlink\">What Are the Steps for eBooks<\/a><\/li>\n<li><a href=\"#keyconcepts\" class=\"my-hyperlink\">Key Concepts<\/a><\/li>\n<li><a href=\"#sdkusageguidelines\" class=\"my-hyperlink\">SDK Usage Guidelines<\/a><\/li>\n<li><a href=\"#personalization\" class=\"my-hyperlink\">Personalization<\/a><\/li>\n<li><a href=\"#contentlicenseacquisition\" class=\"my-hyperlink\">Content License Acquisition<\/a><\/li>\n<li><a href=\"#mediaplayback\" class=\"my-hyperlink\">Media Playback<\/a><\/li>\n<li><a href=\"#msforebooks\" class=\"my-hyperlink\"><span>MediaStream for eBooks<\/span><\/a><\/li>\n<li><a href=\"#otherdrmfunctions\" class=\"my-hyperlink\"><span>Other DRM Functions<\/span><\/a><\/li>\n<li><a href=\"#selectedclasses\" class=\"my-hyperlink\"><span>Selected Classes for Embedded Development<\/span><\/a><\/li>\n<\/ol>\n<\/div>\n<p><!-- ###### CONTENT BODY ####### --><\/p>\n<div id=\"\" class=\"boxslice1 style=\" min-height:=\"0;\"padding-bottom:=\"0;\" >\n<div class=\"anchorlinks-dev\" id=\"whatthesdkcando\">\n<h2>What the SDK can do<\/h2>\n<p>The ExpressPlay Source SDK is designed to make it simple to build highly-customized secure media players and ebook reader applications for Marlin protected audio, video and ebook content.<\/p>\n<p>The Source SDK can be used with iOS, Android, OSX Windows and Linux. The ExpressPlay SDK shares a common core API set across all platforms. On some platforms the SDK includes an extended set of APIs unique to that platform.<\/p>\n<p>For development of media applications on iOS and Android the SDK offers a simple API providing access to DRM control and media playback functions, sufficient to credential an application, acquire DRM licenses and trigger playback of Marlin-protected content. Content may be a contiguous media file or an adaptive bit rate (ABR) stream. The SDK works in conjunction with the ExpressPlay Service for device initialization (Marlin personalization) and token processing for playback (Marlin content license acquisition) while meeting the compliance and robustness rules of the MTMO (Marlin Trust Management Organization).<\/p>\n<\/div>\n<div class=\"anchorlinks-dev\" id=\"whatarethestepstoplay\">\n<h2>What are the steps to play<\/h2>\n<p> The steps below are a high-level view of the steps required to play content. However, the exact sequence of steps to play content in your application may vary due to your embedded platform requirements.<\/p>\n<ul>\n<li>Start the DRM engine<\/li>\n<li>Get a unique player ID (personalization)<\/li>\n<li>Get the content URL<\/li>\n<li>Get a token for playback<\/li>\n<li>Process the token<\/li>\n<li>Start the player<\/li>\n<\/ul><\/div>\n<div class=\"anchorlinks-dev\" id=\"whatarethestepsforebooks\">\n<h3>What are the steps for ebooks<\/h3>\n<ul>\n<li>Initialize the DRM Engine<\/li>\n<li>Get a unique player ID (Personalization)<\/li>\n<li>Get a BB license for the content ID of the ebook, and store that license in the license store<\/li>\n<li>Instantiate a MediaStream object (passing it a reference to the encrypted ebook file)<\/li>\n<li>Read bytes from the mediastream object until there are none remaining.  Now you have a decrypted ebook.<\/li>\n<li>Instantiate a webview object, and pass it the decrypted ebook <\/li>\n<\/ul>\n<\/div>\n<div class=\"anchorlinks-dev\" id=\"keyconcepts\">\n<h2>Key Concepts<\/h2>\n<p>Below is a list of key concepts that a developer should know before using the ExpressPlay SDK. It&#8217;s a good idea to go through all the concepts before using the SDK as they are reference frequently throughout the SDK documentation.<\/p>\n<ul>\n<li><a href=\"\/index.php\/developers\/sdk-key-concepts#whatispersonalization\">What is Personalization<\/a><\/li>\n<li><a href=\"\/index.php\/developers\/sdk-key-concepts#ms3vsbb\">Marlin Simple Stream Setup (MS3) vs. Marlin Broadband Delivery system (BB)<\/a><\/li>\n<li><a href=\"\/index.php\/developers\/sdk-key-concepts#streamingvsoffline\">Streaming vs.Offline<\/a><\/li>\n<li><a href=\"\/index.php\/developers\/sdk-key-concepts#testvsproduction\">Test environment vs. Production environment<\/a><\/li>\n<li><a href=\"\/index.php\/developers\/sdk-key-concepts#supportedformats\">Supported Formats<\/a><\/li>\n<li><a href=\"\/index.php\/developers\/sdk-key-concepts#coreandextendeddrmfunctions\">Core and Extended Digital Rights Management (DRM) Functions<\/a><\/li>\n<\/ul>\n<\/div>\n<p><!-- keyconcepts --><\/p>\n<div class=\"anchorlinks-dev\" id=\"sdkusageguidelines\">\n<h2>SDK Usage Guidelines<\/h2>\n<p>In addition to the key concepts above, the ExpressPlay SDK Usage Guidelines is an overview of best practices when using the ExpressPlay SDK. The major sections of the guidelines are listed below for convenience.<\/p>\n<ul>\n<li><a href=\"\/index.php\/developers\/sdk-usage-guidelines#objectmodel\">Object Model<\/a><\/li>\n<li><a href=\"\/index.php\/developers\/sdk-usage-guidelines#runtimeengine\">Runtime Engine<\/a><\/li>\n<li><a href=\"\/index.php\/developers\/sdk-usage-guidelines#threading\">Threading<\/a><\/li>\n<li><a href=\"\/index.php\/developers\/sdk-usage-guidelines#obtaininghelpforhandlingerrors\">Error Handling<\/a><\/li>\n<\/ul>\n<\/div>\n<p><!-- sdkusageguidelines --><\/p>\n<div class=\"anchorlinks-dev\" id=\"personalization\">\n<h2>Personalization<\/h2>\n<p>Personalization is a Marlin term for device initialization. When an app requests to be personalized by ExpressPlay, it provides a unique fingerprint. The ExpressPlay service, responds by providing the client a credential which is unique to that application copy running on a given device. Without this unique Marlin credential, the device is not able to request tokens for playback.<\/p>\n<p>Additional information on Personalization can be found<br \/>\n<a href=\"\/index.php\/developers\/sdk-key-concepts#overlay-context=developer\/content\/sdk-overview-source\">here.<\/a>\n<\/p>\n<\/div>\n<p><!-- personalization--><\/p>\n<div class=\"anchorlinks-dev\" id=\"contentlicenseacquisition\">\n<h2>Content License Acquisition<\/h2>\n<p>There are two ways to obtain a Marlin content license, using SAS (via MS3) or using a Marlin Broadband (BB) license. Either may be obtained from the ExpressPlay service. You can obtain additional information for MS3 and Marlin BroadBand licenses<br \/>\n<a href=\"\/index.php\/developers\/sdk-key-concepts#overlay-context=developer\/sdk-usage-guidelines\">here.<\/a><\/p>\n<\/div>\n<p><!-- contentlicenseacquisition--><\/p>\n<div class=\"anchorlinks-dev\" id=\"mediaplayback\">\n<h2>Media Playback<\/h2>\n<p>As an example of usage of some of the different ExpressPlay APIs, this section discusses a typical sequence of API usage occurring when playback of a media file or stream is requested on an embedded Linux system.<\/p>\n<p>When such playback is requested, the first thing the application or media stack responsible for playback does is determine what kind of file\/stream it is and whether it is protected. The ExpressPlay SDK Media File component, accessed via WSB_MediaFile methods, can be used to determine this information. If the file\/stream is not protected, the normal media playback functionality for cleartext files can often be used. However, if the file type is understood by ExpressPlay SDK but not by the application or media stack, then ExpressPlay Packager or third-party interfaces may be called to do the parsing.<\/p>\n<p>If the file\/stream is Marlin-protected, the next step needed is to determine whether playback of the content is allowed. This determination requires trying to find a license that grants access to the content. WSB_PlaybackEnabler_EnableMediaFile can be called to obtain a particular media file\u2019s content ID(s) and track IDs (if any) and to find a currently valid license. The Playback Enabler actually invokes the Rights Enabler, which utilizes other interfaces, such as those provided by WSB_LicenseStore as part of its search for a valid license. After such a license is found, other WSB_PlaybackEnabler methods can be called to check that the license allows the content to be played, and to store in a WSB_KeyManager object the key(s) required to decrypt the content.<\/p>\n<p>The WSB_KeyManager_GetKeyByName method can then be called one or more times to obtain from the license the key(s). The application or media stack decrypts the data and sends the samples or the stream in the clear to the rendering engine. In the case of MP4 files, a ExpressPlay Packager class called AP4_SampleDecrypter is sometimes used to do the decryption. On desktop (Windows or Mac) systems, you do not need to directly call methods in any of these classes. Instead, any GUI application you develop can call methods in the WSB_Player class to perform all the Marlin-related functionality. It attempts to find a valid license, obtain the keys needed to decrypt the content, decrypt and decode the content, and supply the resulting cleartext output to whatever window you specify. The WSB_Player methods internally invoke the Media File, Playback Enabler, etc. components as needed.<\/p>\n<\/div>\n<p><!-- mediaplayback--><\/p>\n<div class=\"anchorlinks-dev\" id=\"msforebooks\">\n<h2>MediaStream (MS) for ebooks<\/h2>\n<p>MediaStream interface supports decryption of HTTP or file based encrypted data other than the typical Marlin protected audio\/video media. Which could consist of the eBook media type, where many container formats exist, including a Marlin defined ePub container. In this scenario, either the whole eBook or specific elements of the ebook container can be encrypted and packaged into a type supported by this new interface. The application then parses the container, and uses the interface combined with a Marlin license to decrypt the content.<\/p>\n<p>Additional information for ebooks can be found <a href=\"\/index.php\/developers\/sdk-ebooks#overlay-context=developer\/content\/sdk-overview-ios-and-android\">here.<\/a>\n <\/p>\n<\/div>\n<p><!-- msforebooks--><\/p>\n<div class=\"anchorlinks-dev\" id=\"otherdrmfunctions\">\n<h2>Other DRM Functions<\/h2>\n<p>The Extended DRM functionality is accessible to applications using the source sdk. Including such functions as the ability to access content keys, or query the consequences of a license evaluation (to assess for instance if some form of output controls must be applied and do so as a result). This greater functionality however requires that these applications provide their own security and hardening mechanisms to prevent the loss of key and content material.<\/p>\n<\/div>\n<p><!-- otherdrminfunctions--><\/p>\n<div class=\"anchorlinks-dev\" id=\"selectedclasses\">\n<h2>Selected Classes for Embedded Development<\/h2>\n<p><\/p>\n<h3 style=\"word-wrap: break-word;\">WSB_ActionResultInfo, WSB_ActionResultConstraint,<br \/>\nand WSB_ActionResultOutputControlConstraint<\/h3>\n<p>A WSB_ActionResultInfo object represents information about a SHI_ActionResult that was<br \/>\npreviously obtained, for example, by a call to WSB_PlaybackEnabler_PerformPlayAction.<br \/>\nA SHI_ActionResult provides information about what a license to particular content allows and<br \/>\nrequires for a particular action, such as a \u201cPlay\u201d action. A WSB_ActionResultInfo provides a<br \/>\nhigh-level interface for obtaining the information contained in a SHI_ActionResult, such as<br \/>\nwhether the license allows the specified action (typically content playback), and whether certain<br \/>\nconstraints referred to as obligations and callbacks are placed on applications performing the<br \/>\naction. If an application cannot handle all of the mandatory obligations and callbacks, it is not<br \/>\nallowed to access the content.<\/p>\n<h3>Creating a WSB_ActionResultInfo Object<\/h3>\n<p>A WSB_ActionResultInfo object is created by calling WSB_ActionResultInfo_Create. You<br \/>\npass it a pointer to the SHI_ActionResult you want to analyze (by calling WSB_ActionResultInfo<br \/>\nmethods).<\/p>\n<h3>Determining Whether Content Access Is Allowed<\/h3>\n<p>To determine whether the content license allows the associated action (typically, a \u201cPlay\u201d<br \/>\naction), call WSB_ActionResultInfo_IsGranted. If this method returns WSB_TRUE, the<br \/>\nlicense allows the action.<\/p>\n<p>If a call to WSB_ActionResultInfo_IsPermanent returns WSB_TRUE, the granting of the<br \/>\naction is permanent. Otherwise, it is transient. If it is transient, the application must always<br \/>\nreevaluate the rights, that is, determine whether access is allowed, each time the content is to<br \/>\nbe rendered (played).<\/p>\n<h3>Determining Why Content Access Is Not Allowed<\/h3>\n<p>Whenever an action (such as \u201cPlay\u201d) is not allowed, such as when<br \/>\nWSB_ActionResultInfo_IsGranted returns WSB_FALSE, you can get more information as to<br \/>\nwhy the action was not allowed by calling WSB_ExplainActionResultFailure. Pass this<br \/>\nmethod the following:<\/p>\n<ol>\n<li>A pointer to the SHI_ActionResult.<\/li>\n<li>A pointer to a SHI_Engine (or NULL to have the function create an engine).<\/li>\n<li>A pointer to the WSB_MediaFile, when available, or NULL if not.<\/li>\n<li>The address of a SHI_Data object that is set to contain a goto URL (see below),<br \/>\nwhen relevant. This can be set to NULL if you are not interested in having such a URL.<\/li>\n<\/ol>\n<p>This method examines the SHI_ActionResult and returns an error code that is as meaningful as<br \/>\npossible.<\/p>\n<p>It returns:<\/p>\n<ul>\n<li>WSB_ERROR_DRM_LICENSE_EXPIRED if the license expired.<\/li>\n<li>WSB_ERROR_DRM_SUBSCRIPTION_EXPIRED if the subscription expired.<\/li>\n<li>WSB_ERROR_DRM_PLAY_COUNT_EXCEEDED if the playcount (maximum number of times the content may be played) has been exceeded.<\/li>\n<li>WSB_ERROR_DRM_MISSING_CREDENTIALS if a missing link (such as for subscription link renewal) was detected.<\/li>\n<li>WSB_ERROR_DRM_DENY_RIGHTS if the method could not determine a more useful explanation as to why the action failed.<\/li>\n<li>WSB_SUCCESS if the action was actually granted.<\/li>\n<\/ul>\n<p>Whether or not a goto URL is created, and its semantics, depends on the context. When a subscription has expired, the goto URL is set to a link renewal URL, if possible. In other cases, a rights issuer URL may be returned. Another example of when you might want to call WSB_ExplainActionResultFailure is the following: When handling a license event during a call to WSB_PlaybackEnabler_EnableMediaFile, you will want to determine whether the license that has been found grants the desired action (typically by calling WSB_Config_ValidateActionResult), and if it does not, you may want to call WSB_ExplainActionResultFailure  in order to get an explanation for the failure. One final example is that after calling WSB_PlaybackEnabler_PerformPlayAction, you must determine whether the \u201cPlay\u201d action is actually granted, again typically by calling WSB_Config_ValidateActionResult, and you can call WSB_ExplainActionResultFailure  if desired to learn more if the action was not granted.<\/p>\n<h3>Determining Whether There Are Obligations or Callbacks<\/h3>\n<p>Some licenses may grant access to the content (WSB_ActionResultInfo_IsGranted returns WSB_TRUE), but may specify further requirements that should be satisfied. These requirements are constraints called obligations and callbacks. Obligations represent things that the application should perform or obey. Callbacks are functions that the application should call under specified conditions. Each obligation or callback is either mandatory or optional. If there are any mandatory obligations or callbacks that the application cannot handle, then access to the content is not allowed, even though WSB_ActionResultInfo_IsGranted returned WSB_TRUE.<\/p>\n<p>To determine whether obligations or callbacks are specified, call WSB_ActionResultInfo_HasObligations or WSB_ActionResultInfo_HasCallbacks, respectively. Each of these methods returns WSB_TRUE if there are any of the specified constraints (obligations or callbacks), whether mandatory or optional. To determine whether there are any mandatory obligations or callbacks, call WSB_ActionResultInfo_HasMandatoryObligations or WSB_ActionResultInfo_HasMandatoryCallbacks, respectively.<\/p>\n<h3>Obtaining Obligations<\/h3>\n<p>Call WSB_ActionResultInfo_GetConstraintCount to find out how many constraints there are.<br \/>\nThis method has a WSB_Boolean argument which, if WSB_TRUE, indicates that the method<br \/>\nshould return a count of just the mandatory constraints; otherwise, it returns a count of all the<br \/>\nconstraints. Please note: Currently, this method only counts obligations, not callbacks.<\/p>\n<p>You can iterate through the constraints (currently, only obligations), obtaining one at a time.<br \/>\nPass WSB_ActionResultInfo_GetConstraintByIndex the (0-based) index for the constraint to<br \/>\nbe obtained, a WSB_Boolean indicating whether only mandatory constraints should be<br \/>\nreturned, and the address of a pointer to a WSB_ActionResultConstraint.<\/p>\n<p>WSB_ActionResultInfo_GetConstraintByIndex will create a WSB_ActionResultConstraint for the<br \/>\nspecified constraint and set the pointer to refer to this object. Here is an example of obtaining<br \/>\nthe count of mandatory constraints and iterating through the constraints. In this example,<br \/>\nAR_info is a pointer to the WSB_ActionResultInfo:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>WSB_Cardinal count = 0;<br \/>\nWSB_Ordinal indx;<br \/>\nWSB_Result result;<br \/>\nWSB_ActionResultConstraint* constraint = NULL;<\/p>\n<p>count = WSB_ActionResultInfo_GetConstraintCount(AR_info,<br \/>\nWSB_TRUE);<br \/>\nif (count &gt; 0) {<br \/>\n\/* There are mandatory constraints, let's see what they are *\/<br \/>\nfor (indx = 0; indx &lt; count; indx++) {<br \/>\nresult =<br \/>\nWSB_ActionResultInfo_GetConstraintByIndex(AR_info,<br \/>\nWSB_TRUE,<br \/>\nindx,<br \/>\n&amp;constraint);<br \/>\nif (WSB_FAILED(result)) {<br \/>\n\/* Handle error *\/<br \/>\n. . .;<br \/>\n}<br \/>\n\/* We have a constraint. Get more info about it. *\/<br \/>\n. . .;<br \/>\n}<br \/>\n}<\/code>\n<\/div>\n<p>You can call WSB_ActionResultConstraint methods to obtain further information about each<br \/>\nconstraint obtained. <\/p>\n<h3>Explicitly Accepting Obligations or Callbacks<\/h3>\n<p>In most cases, after the application has determined that it can handle (at least) all the<br \/>\nmandatory obligations and callbacks, it must explicitly indicate this, for example, by calling<br \/>\nWSB_PlaybackEnabler_AcceptActionResult, prior to accessing the content. To determine<br \/>\nwhether explicitly accepting the constraints is actually a requirement, call<br \/>\n<b>WSB_ActionResultInfo_MustAccept.<\/b><\/p>\n<h3>Destroying the WSB_ActionResultInfo<\/h3>\n<p>When the WSB_ActionResultInfo object is no longer needed, destroy it by calling<br \/>\nWSB_ActionResultInfo_Destroy.<\/p>\n<h3 style=\"word-wrap: break-word;\">WSB_ActionResultConstraint and WSB_ActionResultOutputControlConstraint Methods<\/h3>\n<p style=\"word-wrap: break-word;\">A WSB_ActionResultConstraint object represents a single constraint associated with a SHI_ActionResult.<\/p>\n<p style=\"word-wrap: break-word;\">A WSB_ActionResultOutputControlConstraint object is a specialized case of a WSB_ActionResultConstraint that represents a single output control constraint.<br \/>\nUsage of WSB_ActionResultConstraint and WSB_ActionResultOutputControlConstraint.<\/p>\n<h3>Obtaining WSB_ActionResultConstraint Objects<\/h3>\n<p>A WSB_ActionResultConstraint is created whenever WSB_ActionResultInfo_GetConstraintByIndex is called.<\/p>\n<p style=\"word-wrap: break-word;\">A WSB_ActionResultOutputControlConstraint is an existing WSB_ActionResultConstraint object simply recast to WSB_ActionResultOutputControlConstraint (by WSB_ActionResultConstraint_GetAsOutputControlConstraint) when it is determined that the object is a constraint with the output control type, as described below.<\/p>\n<h3>Determining the Type and Nature of the Constraint<\/h3>\n<p>Call WSB_ActionResultConstraint_IsMandatory to find out whether the constraint is mandatory.<\/p>\n<p>Call WSB_ActionResultConstraint_Type to obtain the constraint type. The possible constraint types are defined in WsbActionResultConstraint.h. Currently, they are the following:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>WSB_ACTION_RESULT_CONSTRAINT_TYPE_UNKNOWN<br \/>\nWSB_ACTION_RESULT_CONSTRAINT_TYPE_DO_NOT_STORE<br \/>\nWSB_ACTION_RESULT_CONSTRAINT_TYPE_OUTPUT_CONTROL<br \/>\nWSB_ACTION_RESULT_CONSTRAINT_TYPE_METERING<\/code>\n<\/div>\n<p>A DO_NOT_STORE obligation means that it is forbidden to store the content on the device; it<br \/>\ncan only be streamed.<\/p>\n<p>A METERING obligation indicates that the application must perform metering to report the start and stop times of content playing, as described in the Sushi (Marlin Client) SDK API document. OUTPUT_CONTROL obligations are described in the following section.<\/p>\n<h3>Handling an Output Control Obligation<\/h3>\n<p style=\"word-wrap: break-word;\">An OUTPUT_CONTROL constraint specifies an output control obligation. An output control obligation is characterized by three elements: a technology, a parameter, and a value. When you receive a WSB_ActionResultConstraint of this type, call WSB_ActionResultConstraint_GetAsOutputControlConstraint to cast it to a WSB_ActionResultOutputControlConstraint so that you can access this further information. Call WSB_ActionResultOutputControlConstraint_GetTechnology to obtain the technology type. The possible technology types are defined in WsbActionResultConstraint.h with the following names:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>WSB_ACTION_RESULT_CONSTRAINT_OUTPUT_CONTROL_TECHNOLOGY_UNKNOWN<br \/>\nWSB_ACTION_RESULT_CONSTRAINT_OUTPUT_CONTROL_TECHNOLOGY_BASIC_CCI<br \/>\nWSB_ACTION_RESULT_CONSTRAINT_OUTPUT_CONTROL_TECHNOLOGY_DTCP<\/code>\n<\/div>\n<p style=\"word-wrap: break-word;\">Call WSB_ActionResultOutputControlConstraint_GetParameter to obtain the parameter type, one of the following:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>WSB_ACTION_RESULT_CONSTRAINT_OUTPUT_CONTROL_PARAM_UNKNOWN<br \/>\nWSB_ACTION_RESULT_CONSTRAINT_OUTPUT_CONTROL_PARAM_EPN<br \/>\nWSB_ACTION_RESULT_CONSTRAINT_OUTPUT_CONTROL_PARAM_CCI<br \/>\nWSB_ACTION_RESULT_CONSTRAINT_OUTPUT_CONTROL_PARAM_IMAGE_CONSTRAINT_TOKEN<br \/>\nWSB_ACTION_RESULT_CONSTRAINT_OUTPUT_CONTROL_PARAM_DIGITAL_ONLY_TOKEN<br \/>\nWSB_ACTION_RESULT_CONSTRAINT_OUTPUT_CONTROL_PARAM_APS<br \/>\nWSB_ACTION_RESULT_CONSTRAINT_OUTPUT_CONTROL_PARAM_RETENTION_MOVE_MODE<br \/>\nWSB_ACTION_RESULT_CONSTRAINT_OUTPUT_CONTROL_PARAM_RETENTION_STATE<\/code>\n<\/div>\n<p style=\"word-wrap: break-word;\">Call WSB_ActionResultOutputControlConstraint_GetValue to obtain the integer value associated with the output control technology and parameter. For possible values, see the Marlin Output Control Specification.<\/p>\n<h3>Destroying the WSB_ActionResultConstraint<\/h3>\n<p>When a WSB_ActionResultConstraint object is no longer needed, destroy it by calling WSB_ActionResultConstraint_Destroy.<\/p>\n<\/div>\n<p><!-- selectedclassusage--><\/p>\n<div id=\"wsb_config\">\n<h2>WSB_Config<\/h2>\n<h3>Usage<\/h3>\n<p>The WSB_Config methods are ones whose default implementations can be replaced and customized for different platforms. Currently, there is only one such method: WSB_Config_ValidateActionResult.<\/p>\n<p>WSB_Config_ValidateActionResult can be called to analyze a SHI_ActionResult. A SHI_ActionResult is obtained, for example, when WSB_PlaybackEnabler_PerformPlayAction is called. A SHI_ActionResult is also obtained whenever a license is found during a license search initiated by a call to WSB_PlaybackEnabler_EnableMediaFile or WSB_RightsEnabler_EnableMediaFile.<\/p>\n<p>The SHI_ActionResult contains information about access rights and requirements that must be satisfied prior to playing the relevant content (such as the content for which a license was being searched). These requirements include constraints referred to as obligations and callbacks. Obligations represent things that the application is required to perform or obey. Callbacks are functions that the application is required to call under specified conditions.<\/p>\n<p>WSB_Config_ValidateActionResult has four parameters:<\/p>\n<ol>\n<li>A pointer to the SHI_ActionResult you want analyzed.<\/li>\n<li>A WSB_Boolean whose value should be WSB_TRUE if the SHI_ActionResult was generated as a result of a SHI_Action_Perform (which is the case if it was generated by a call to WSB_PlaybackEnabler_PerformPlayAction). The value should be WSB_FALSE if the SHI_ActionResult was generated as a result of a SHI_Action_Check, which is the case whenever a license is found during a license search.<\/li>\n<li>The name of an action. WSB_Config_ValidateActionResult determines whether the specified action is allowed. Typically, you want to know whether playback of the content is allowed, so for this parameter you specify SHI_ACTION_PLAY. The text below assumes you have specified this action.<\/li>\n<li>Any parameters required by the action. This is typically NULL, since the Play action does not have any parameters. WSB_Config_ValidateActionResult calls WSB_ActionResultInfo_Create, passing it the SHI_ActionResult, and then subsequently calls WSB_ActionResultInfo methods to determine whether the Play action is allowed (that is, whether the content governed by the license is allowed to be played) and whether all of the mandatory obligations and callbacks (if any) can be satisfied. If the action is granted and all mandatory obligations and callbacks can be satisfied, WSB_Config_ValidateActionResult returns WSB_SUCCESS. If the action is not granted, it returns WSB_ERROR_DRM_DENY_RIGHTS, and it returns<br \/>\nWSB_ERROR_DRM_LICENSE_UNSUPPORTED if there are mandatory callbacks or obligations that cannot be satisfied. If the Play action is not granted, you can call WSB_ExplainActionResultFailure to get a more detailed error code as to why the action is not granted.<\/li>\n<\/ol>\n<h3>WSB_Config_ValidateActionResult Default and Sample Implementations<\/h3>\n<p style=\"word-wrap: break-word;\">WSB_Config_ValidateActionResult is a replaceable function. That is, there is a default implementation, but that implementation can be replaced prior to building Wasabi. The header file declaring the function is at<br \/>\n$WASABI_HOME\/Source\/Config\/Validator\/WsbConfigActionResultValidator.h The default implementation is at<br \/>\n$WASABI_HOME\/Source\/Config\/Validator\/Default\/WsbConfigActionResultValidator.cpp The default implementation refuses access to the content if either the Play action is not granted or there are any mandatory obligations or callbacks.<\/p>\n<p style=\"word-wrap: break-word;\">There is also a sample more complex implementation at $WASABI_HOME\/Source\/Config\/Validator\/Sample\/WsbConfigActionResultValidator.cpp This sample validator allows mandatory DTCP output control obligations and MS3 do-not-store obligations, which are described further in the sample .cpp file and in the Marlin Output Control Specification. It also allows BasicCCI DigitalOnlyToken and APS parameter values. The sample code cannot be used as is. It shows how to allow such obligations, but the code must in addition in some cases take actions required to properly enforce the specified constraints. For example, if the device supports CGMS-A (for the Analog Protection System), then allowing the BasicCCI APS parameter is okay, as long as the corresponding output control flags have been set in the device hardware or software.<\/p>\n<p>The default validator can always be used for an application that does not support any obligations or callbacks. If an application could actually support some obligations or callbacks, or the device has characteristics that would make a particular obligation or callback irrelevant, then the default validator should be replaced with a more suitable validator. For example, if a device would never store MS3 content, then a mandatory do-not-store obligation could be considered to be satisfied, and the existence of such an obligation should not result in denying access to the content.<\/p>\n<\/div>\n<p><!-- wsb_config--><\/p>\n<div id=\"wsb_ecmdecrypter\">\n<h2>WSB_EcmDecrypter<\/h2>\n<h3>Usage<\/h3>\n<p>A WSB_EcmDecrypter object can be used to aid an application processing a Marlin Broadband Transport Stream (Marlin BBTS), which is an MPEG-2 Transport Stream containing Marlin-protected content. The WSB_EcmDecrypter interface contains methods for processing PMTs (Program Map Tables), ECMs (Entitlement Control Messages), CATs (Conditional Access Tables), and MRTs (Marlin Rights Tables), supplying the client information needed, such as the traffic keys required to decrypt the Transport Stream media content packets. Usage of WSB_EcmDecrypter is illustrated in the example utility named WasabiEcmDecrypter.cpp.<\/p>\n<h3>Creating a WSB_EcmDecrypter Object<\/h3>\n<p>Call WSB_EcmDecrypter_Create to create an instance of a WSB_EcmDecrypter object. You pass it the address of a WSB_EcmDecrypter pointer that is set by this method to refer to the WSB_EcmDecrypter object that the method creates. You also pass it an indication of the format in which you want the traffic keys supplied, either WSB_MP2TS_KEY_FORMAT_CLEAR (indicating cleartext 16-byte AES keys, with 16-byte initialization vectors) or WSB_MP2TS_KEY_FORMAT_SKB (indicating Secure Key Box-exported keys, that is, keys exported using the SKB API SKB_SecureData_Export method). There is also a parameter for specifying key format parameters, but there are not yet any such parameters defined, so currently just specify NULL for key_format_params. Also pass WSB_EcmDecrypter_Create a \u201clistener\u201d that is notified of events occurring while the WSB_EcmDecrypter_UpdateEcm and WSB_EcmDecrypter_UpdateMrt methods are processing ECMs (known as KSMTs in IEC 62455) and MRTs (Marlin Rights Tables), respectively. A listener is declared as follows:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef struct {<br \/>\n\/** Listener instance pointer; gets passed into callback<br \/>\n* methods.<br \/>\n*\/<br \/>\nvoid* instance;<br \/>\n\/**<br \/>\n* Callback method invoked on a new or updated media file<br \/>\n* detection.<br \/>\n*\/<br \/>\nWSB_Result (*OnNewMediaFile)(void* instance,<br \/>\nWSB_MediaFile* media_file,<br \/>\nWSB_KeyManager* key_manager);<br \/>\n\/**<br \/>\n* Callback method invoked on a new MPEG2 TS traffic key.<br \/>\n*\/<br \/>\nvoid (*OnKsmInfoChange)(void* instance,<br \/>\nconst WSB_KsmInfo* key_info,<br \/>\nWSB_UInt32 change_mask);<br \/>\n} WSB_EcmDecrypter_Listener;<\/code>\n<\/div>\n<h3>WSB_EcmDecrypter Methods and Usage<\/h3>\n<p>The WSB_EcmDecrypter interface has four methods that facilitate the processing of Marlin BBTS streams: WSB_EcmDecrypter_UpdatePmt, <\/p>\n<p>WSB_EcmDecrypter_UpdateEcm, WSB_EcmDecrypter_UpdateCat, and WSB_EcmDecrypter_UpdateMrt. A client basically processes a Marlin BBTS stream the same way it processes any MPEG-2 TS stream whose content it plays, except for needing to do a few Marlin-specific steps. One of the first things the client should do is create a WSB_PlaybackEnabler object that is needed in subsequent steps.<\/p>\n<p>Here is an example call:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>WSB_PlaybackEnabler* enabler = NULL;<br \/>\nWSB_PlaybackEnabler_Create(enabler_listener, &amp;enabler);<\/code>\n<\/div>\n<p>The client should also create a WSB_EcmDecrypter, after first defining the listener callback methods that are called by the WSB_EcmDecrypter when it is processing an ECM. These callback methods are described below. Sample code for creation of a WSB_EcmDecrypter object is the following:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>WSB_EcmDecrypter* ecm_dec = NULL;<br \/>\nWSB_EcmDecrypter_Create(<br \/>\necm_listener, WSB_MP2TS_KEY_FORMAT_CLEAR, NULL, &amp;ecm_dec);<\/code>\n<\/div>\n<p>The client should have a URL to the content to be played. If there is any chance the URL is an MS3 (Marlin Simple Secure Streaming) URL, WSB_PlaybackEnabler_ResolveUrl should be called. Here&#8217;s a sample call, where url is the original URL, and content_url is a pointer to where the method stores the content URL (which is the same as the original URL, if it was not an MS3 URL):<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>SHI_Data* content_url = NULL;<br \/>\nWSB_PlaybackEnabler_ResolveUrl(enabler, url, &amp;content_url);<\/code>\n<\/div>\n<p>The client should then use the content URL to obtain the content, and should start processing it<br \/>\nas usual, for example extracting PAT and PMT tables.<\/p>\n<h3>Processing PMTs and ECMs<\/h3>\n<p>The WSB_EcmDecrypter_UpdatePmt method should be called by the client to process a PMT (Program Management Table). Pass it a pointer to the table bytes and an indication of the number of bytes. This method extracts from the PMT useful information it may need later, such as the CA descriptor, and returns to the caller the PID (Packet ID) of the ECMs (Entitlement Control Messages) for the program referenced by the PMT. Here is a sample call:<br \/>\nWSB_EcmDecrypter_UpdatePmt(ecm_dec, pmt, pmt_length, &amp;ecm_pid);<\/p>\n<p>For each ECM with that PID, the client should call WSB_EcmDecrypter_UpdateEcm, providing it a pointer to the ECM bytes and an indication of the number of bytes. Here is a sample call:<\/p>\n<p>WSB_EcmDecrypter_UpdateEcm(ecm_dec, ecm, ecm_length);<\/p>\n<p>This method processes the ECM. Whenever it encounters a new content ID specified in the ECM, it calls the WSB_EcmDecrypter listener method OnNewMediaFile, passing it a pointer to a WSB_MediaFile object representing the content, and a pointer to a WSB_KeyManager in which the keys needed to decrypt the Marlin content should be stored. The OnNewMediaFile method must try to \u201cenable\u201d the new media file through the WSB_PlaybackEnabler API, ensuring that a license for the content is found and evaluated to determine whether playback of the content is allowed, and, if so, also ensuring that the WSB_KeyManager object is filled in with the keys needed to decrypt the content. Sample pseudocode is the following, where enabler is assumed to be the WSB_PlaybackEnabler object previously created by a call to WSB_PlaybackEnabler_Create:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>ecm_listener.OnNewMediaFile(media_file, key_manager) {<br \/>\n\/\/ Try to have a valid license for the content found:<br \/>\nWSB_PlaybackEnabler_EnableMediaFile(<br \/>\nenabler, media_file, NULL, 0);<\/p>\n<p>\/\/ If a license was found, determine whether playback is allowed:<br \/>\nWSB_PlaybackEnabler_PerformPlayAction(enabler, &amp;action_result);<\/p>\n<p>\/\/ Handle any DRM\/license issues here.<br \/>\n\/\/ Determine whether app can handle all critical obligations<br \/>\n\/\/ and callbacks... If so, and playback is allowed, call the<br \/>\n\/\/ following to obtain the content keys and supply them to<br \/>\n\/\/ the WSB_KeyManager:<br \/>\nWSB_PlaybackEnabler_AcceptActionResult(<br \/>\nenabler, key_manager, NULL);<br \/>\n}<\/code>\n<\/div>\n<p>Whenever WSB_EcmDecrypter_UpdateEcm encounters in the ECM a new traffic key and any other ECM\/KSM information changes, it decrypts the traffic key (which was encrypted using the Marlin content key) and it calls the listener\u2019s OnKsmInfoChange method, passing it a WSB_KsmInfo structure and a change mask indicating which of the WSB_KsmInfo fields have been modified since the last time OnKsmInfoChange was called. The WSB_KsmInfo structure is defined as follows:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef struct {<br \/>\n\/**<br \/>\n* A set of WSB_KsmInfoFlag values, bitwise or'ed together,<br \/>\n* indicating which fields of the structure were present in the<br \/>\n* ECM.<br \/>\n*\/<br \/>\nWSB_UInt32 present_mask;<br \/>\nWSB_Mpeg2TsTrafficKey_Format format;<br \/>\nconst void* format_params;<br \/>\nWSB_Mpeg2TsTrafficKey_Parity current_key_parity;<br \/>\nconst WSB_Byte* current_key;<br \/>\nWSB_Size current_key_size;<br \/>\nconst WSB_Byte* current_iv;<br \/>\nWSB_Size current_iv_size;<br \/>\nconst WSB_Byte* next_key;<br \/>\nWSB_Size next_key_size;<br \/>\nconst WSB_Byte* next_iv;<br \/>\nWSB_Size next_iv_size;<br \/>\nWSB_Mpeg2TsTrafficKey_ProtectionSystem protection;<br \/>\nWSB_Size access_criteria_count;<br \/>\nWSB_UInt64 timestamp;<br \/>\nWSB_UInt8 key_lifetime;<br \/>\nWSB_UInt8 permissions_category;<br \/>\n} WSB_KsmInfo;<\/code>\n<\/div>\n<p>The current_key_parity indicates whether the key specified by current_key is an even key (if the value is WSB_ MP2TS_KEY_EVEN) or an odd key (WSB_ MP2TS_KEY_ODD). As you can see, the current key, and the next key, and their initialization vectors, are specified, as well as other information such as access criteria and timestamps, whose meanings and usage are defined in the Marlin BBTS Specification.<\/p>\n<p>The OnNewKsmInfo method should do whatever it needs to do to utilize the new traffic key and other information, so that it can decrypt subsequent TS content packets using the appropriate key.<\/p>\n<h3>Processing CATs and MRTs<\/h3>\n<p>The WSB_EcmDecrypter_UpdateCat method should be called by the client to process a CAT (Conditional Access Table). Pass it a pointer to the table bytes and an indication of the number of bytes. This method extracts from the CAT useful information it may need later, and returns to the caller (in the final parameter pointed to by the call) the PID (Packet ID) of the MRT (Marlin Rights Table).<\/p>\n<p>Here is a sample call:<\/p>\n<p>WSB_EcmDecrypter_UpdateCat(ecm_dec, cat, cat_length, &amp;mrt_pid); <\/p>\n<p>For each MRT with that PID, the client should call WSB_EcmDecrypter_UpdateMrt, providing it a pointer to the MRT bytes and an indication of the number of bytes. <\/p>\n<p>Here is a sample call:<\/p>\n<p>WSB_EcmDecrypter_UpdateMrt(ecm_dec, mrt, mrt_length);<\/p>\n<p>This method processes the MRT. Whenever it encounters a new Silent License Acquisition URL, it calls the WSB_EcmDecrypter listener method OnNewMediaFile, passing it a pointer to a WSB_MediaFile object representing the content, and a pointer to a WSB_KeyManager in which the keys needed to decrypt the Marlin content should be stored. If the client has already found a license for the specified content, the OnNewMediaFile method can simply ignore the<br \/>\ncall. Otherwise, the passed-in WSB_MediaFile will now include the Silent License Acquisition URL, which may make it possible to now obtain the license when<br \/>\nWSB_PlaybackEnabler_EnableMediaFile is called. OnNewMediaFile should call that method and, if successful, call the other methods shown in the sample OnNewMediaFile shown above, to determine whether playback is allowed and to fill in the WSB_KeyManager with the content keys.<\/p>\n<h3>Destroying the WSB_EcmDecrypter<\/h3>\n<p>When you are done with the WSB_EcmDecrypter object, destroy it by calling WSB_EcmDecrypter_Destroy.<\/p>\n<\/div>\n<p><!-- wsb_ecmdecrypter--><\/p>\n<div id=\"wsb_keymanager\">\n<h2>WSB_KeyManager<\/h2>\n<h3>Usage<\/h3>\n<p>A WSB_KeyManager object can be used to get content keys for a playback session. Call WSB_KeyManager_CreateEx to create an instance of a WSB_KeyManager object, passing it a WSB_ContentKeyFormatInfo structure indicating the format in which content keys should be stored in the WSB_KeyManager.\n<\/p>\n<p>This structure is defined as follows:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef struct {<br \/>\nWSB_ContentKeyFormat format;<br \/>\nconst void* parameters;<br \/>\n\/**&lt; NULL except for format WSB_CONTENT_KEY_FORMAT_SKB_CUSTOM *\/<br \/>\n} WSB_ContentKeyFormatInfo;<br \/>\n<\/code>\n<\/div>\n<p>WSB_ContentKeyFormat is one of the following:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef enum {<br \/>\nWSB_CONTENT_KEY_FORMAT_CLEARTEXT,<br \/>\nWSB_CONTENT_KEY_FORMAT_SKB_STANDARD,<br \/>\nWSB_CONTENT_KEY_FORMAT_SKB_CUSTOM<br \/>\n} WSB_ContentKeyFormat;<\/code>\n<\/div>\n<p>Here, SKB refers to Secure Key Box, and the standard and custom SKB formats are as defined in the SKB API. Calling WSB_KeyManager_Create will create an instance of a WSB_KeyManager object in which the content key format is WSB_CONTENT_KEY_FORMAT_CLEARTEXT. The WSB_KeyManager_GetContentKeyFormatInfo method can be called to obtain the WSB_ContentKeyFormatInfo for the passed-in WSB_KeyManager. To obtain a particular key that has been stored in the WSB_KeyManager (by the Playback Enabler), call WSB_KeyManager_GetKeyByName. You pass it a string representing the \u201cname\u201d of the key. <\/p>\n<p>This string could be one of the following:<\/p>\n<ol>\n<li>A content ID.<\/li>\n<li>\u201c@track.n\u201d, where n is the track ID (e.g., \u201c@track.1\u201d), for content that has a track-based protection scheme.<\/li>\n<li>\u201c@file\u201d for content that has a file-based protection scheme.<\/li>\n<\/ol>\n<p>You also pass, in the key_data parameter, a pointer to a buffer in which the key data should be written, and, in the key_data_size parameter, an indication of the buffer size. The key length can be queried by setting key_data to NULL. That is, if you pass NULL for the key_data buffer pointer, this method simply returns the key length in *key_data_size, and returns WSB_SUCCESS.<\/p>\n<p>At any given time, the WSB_KeyManager is considered to hold the keys for a particular media file. Whenever you want to reuse it to hold the keys for a different media file, first call WSB_KeyManager_Clear to clear its context and remove the keys it currently holds.<\/p>\n<p>When you are done with the WSB_KeyManager object, destroy it by calling WSB_KeyManager_Destroy.<\/p>\n<\/div>\n<p><!-- wsb_keymanager--><\/p>\n<div id=\"wsb_licensestoreandwsb_license\">\n<h2>WSB_LicenseStore and WSB_License<\/h2>\n<p>A WSB_LicenseStore object is used to access the Wasabi License Store database in which licenses may be stored. Its methods can be called to store licenses, to obtain licenses that are stored, and to remove licenses from the License Store.<\/p>\n<h3>Obtaining a WSB_LicenseStore Object<\/h3>\n<p>The WSB_LicenseStore_Open method is called to open the License Store and create a new WSB_LicenseStore object to refer to it. If the License Store (database) does not yet exist, it is created.<\/p>\n<h4>WSB_LicenseStore Methods<\/h4>\n<p>Once the License Store is open, WSB_LicenseStore_AddLicense can be called to add a license into the License Store. In the call, you specify the license data and its size, as well as an optional tag string in which you can specify whatever textual information you like, such as the name of the application that is adding the license to the License Store. This method returns the license ID assigned by the License Store to the license that was added.<\/p>\n<p>WSB_LicenseStore_RemoveLicense removes from the License Store the license with a specified license ID.<\/p>\n<p>WSB_LicenseStore_GetLicenseById can be called to obtain from the License Store a license with a particular license ID.<\/p>\n<p>WSB_LicenseStore_FindLicensesByContentIds is passed an array of one or more content IDs, and it finds in the License Store the license(s) with the specified content ID(s). It returns a SHI_Data object of type SHI_DATA_TYPE_ARRAY containing the licenses. If you call the method with an empty content ID list, all licenses in the License Store are returned, but please note that it is far better to instead call WSB_LicenseStore_EnumerateLicenses to obtain all the licenses and control which license-related data is included, especially if there are a large number of licenses in the License Store.<\/p>\n<p>WSB_LicenseStore_FindContentIdsByLicense is passed a license ID and returns an array of the content ID(s) governed by the license with the specified license ID. WSB_LicenseStore_EnumerateLicenses obtains from the License Store an array of WSB_License objects representing all the licenses in the License Store. Since there may be a large number of licenses in the License Store, it may be useful to reduce the amount of memory required for each of the returned WSB_License objects by specifying, in a flags parameter, which license-related data (the bytes for the license, the expiration date, the insertion date, and\/or the tag) you want to be included. Any such items whose corresponding value is not set in the flags parameter is not included. WSB_LicenseStore_EnumerateContentIds obtains from the License Store an array of all content IDs governed by the licenses in the License Store.<\/p>\n<p>When you are done with the WSB_LicenseStore object, close the License Store and release the WSB_LicenseStore by calling WSB_LicenseStore_Close.<\/p>\n<h3>WSB_License Methods<\/h3>\n<p>A WSB_License object represents information about a license. WSB_License objects are created as a result of calls to WSB_LicenseStore_GetLicenseById<br \/>\n(which obtains the license with a specified ID), WSB_LicenseStore_FindLicensesByContentIds, (which obtains the license or licenses with<br \/>\nspecified content IDs), and WSB_LicenseStore_EnumerateLicenses (which obtains all licenses in the License Store). The WSB_License objects are pointed to from a structure in the SHI_Data returned by those methods. The caller is responsible for calling SHI_Data_Release to release the SHI_Data object when it is no longer needed. The WSB_License objects pointed to from the SHI_Data are also freed by the SHI_Data_Release call.\n<\/p>\n<h4>WSB_License Methods<\/h4>\n<p>Various methods can be called to obtain information about a particular license. In most cases, the specified WSB_License passed as a parameter has the requested information and will return it. However, if the license was obtained as one of the licenses returned by a call to WSB_LicenseStore_EnumerateLicenses, and the flags in that call did not indicate that the specified type of information should be included, then a suitable return value, such as a NULL or a -1, indicates that such data is not available through that particular WSB_License.<\/p>\n<p>Call WSB_License_GetId to obtain the license ID for the license referenced by a particular WSB_License.<\/p>\n<p>WSB_License_GetExpirationDate returns the license expiration date. The value is represented as the number of UTC (Coordinated Universal Time) minutes since January 1, 1970.<\/p>\n<p>WSB_License_GetInsertionDate returns the time when the license was added to the License Store. As with WSB_License_GetExpirationDate, the value is represented as the number of UTC minutes since January 1, 1970. WSB_License_GetData returns a byte array containing the bytes representing the license.<br \/>\nWSB_License_GetTag returns the license tag for a specified license. A license tag can be set when a license is added to the License Store (see WSB_LicenseStore_AddLicense). It is simply a NULL-terminated character string that could, for example, indicate the name of the application that inserted the license. WSB_License_GetPriority is not currently used.<\/p>\n<\/div>\n<p><!-- wsb_licensestoreandwsb_license--><\/p>\n<div id=\"wsb_mediafileandwsb_trackinfo\">\n<h2>WSB_MediaFile and WSB_TrackInfo<\/h2>\n<p>A WSB_MediaFile object can be used to obtain information about a media file, to embed a license within a media file, and to obtain a license embedded within a media file.\n<\/p>\n<h4>Obtaining a WSB_MediaFile Object<\/h4>\n<p>Call WSB_MediaFile_Open to open a specified media file and create a WSB_MediaFile object referencing it. Pass it either a filename or an HTTP URL. If you know the MIME type, pass that as well.\n<\/p>\n<h4>Obtaining File Information<\/h4>\n<p>A WSB_MediaFile is used to obtain various types of information about the media file it references. WSB_MediaFile_GetName returns the file name, WSB_MediaFile_GetProtectionType returns the protection type (indicating whether it is a DCF file, a PDCF file, etc.), and WSB_MediaFile_GetContentType returns the file\u2019s content type as a MIME type. The MIME type represents the media data type before protection. The following constants are defined for<br \/>\nthis property:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>#define WSB_CONTENT_TYPE_VIDEO_MP4      \"video\/mp4\"<br \/>\n#define WSB_CONTENT_TYPE_AUDIO_MP4      \"audio\/mp4\"<br \/>\n#define WSB_CONTENT_TYPE_VIDEO_MPEG2TS  \"video\/MP2T\"<br \/>\n#define WSB_CONTENT_TYPE_DASH           \"application\/dash+xml\"<br \/>\n#define WSB_CONTENT_TYPE_HLS            \"application\/vnd.apple.mpegurl\"<br \/>\n#define WSB_CONTENT_TYPE_DCF            \"application\/vnd.oma.drm.dcf\"<br \/>\n#define WSB_CONTENT_TYPE_DECE           \"video\/vnd.dece.mp4\"<\/code>\n<\/div>\n<p><b>Note:<\/b> MIME types are case-insensitive.<\/p>\n<p>If the protection type is WSB_PROTECTION_TYPE_DCF, you can call WSB_MediaFile_GetContentId to obtain the content ID for the content in the media file. This is only relevant for DCF files, which have a single content ID, reported at the file level. For files that do not have a content ID at the file level (e.g., PDCF files, which report content IDs on a per-track basis), this method returns NULL. To obtain the content ID for a particular track in a PDCF file, create a WSB_TrackInfo object referencing the track (see \u201cTrack Related Methods\u201d below) and then call WSB_TrackInfo_GetContentId. <\/p>\n<p>Call WSB_MediaFile_GetProgress to find out the total number of bytes for the file (if known) and the number that are currently available, which are less than the total number if the file is currently being downloaded. If the type of media doesn\u2019t enable gathering the total size information, such as in streaming, the total number of bytes reported is zero.<\/p>\n<p>Call WSB_MediaFile_GetMetadata to obtain the metadata for the file, indicating information such as the album, artist, lyrics, copyright, and so on. You pass this method the address of a SHI_Attribute pointer that is set to point to a SHI_Attribute object containing the metadata. The SHI_Attribute type is SHI_ATTRIBUTE_TYPE_LIST, and each child of the list is an attribute for a single metadata item. The caller is responsible for calling SHI_Attribute_Release to release the SHI_Attribute object when it is no longer needed.<\/p>\n<h3>Obtaining Media Information<\/h3>\n<p>If you call WSB_MediaFile_GetMediaInfo, passing it a pointer to a WSB_MediaInfo structure, it will fill in that structure with the following information:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef struct WSB_MediaInfo {<br \/>\nWSB_MediaType type;<br \/>\nWSB_MediaFormat format;<br \/>\nWSB_UInt32 duration; \/**&lt; in ms *\/<br \/>\nWSB_UInt32 bitrate; \/**&lt; in bits\/sec *\/<br \/>\nWSB_StreamEncryptionMethod encryption_method;<br \/>\nunion {<br \/>\nWSB_AudioMediaInfo audio;<br \/>\nWSB_VideoMediaInfo video;<br \/>\n} specific;<br \/>\n} WSB_MediaInfo;<\/code>\n<\/div>\n<p>The structures referenced by WSB_MediaInfo are the following:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef enum {<br \/>\nWSB_MEDIA_TYPE_UNKNOWN = 0,<br \/>\nWSB_MEDIA_TYPE_AUDIO = 1,<br \/>\nWSB_MEDIA_TYPE_VIDEO = 2<br \/>\n} WSB_MediaType;<\/p>\n<p>typedef enum {<br \/>\nWSB_MEDIA_FORMAT_UNKNOWN = 0,<br \/>\nWSB_MEDIA_FORMAT_AAC = 1,<br \/>\nWSB_MEDIA_FORMAT_AVC = 2,<br \/>\nWSB_MEDIA_FORMAT_MP3 = 3,<br \/>\nWSB_MEDIA_FORMAT_MPEG4_VID = 4<br \/>\n} WSB_MediaFormat;<\/p>\n<p>typedef enum {<br \/>\nWSB_STREAM_ENCRYPTION_METHOD_UNKNOWN = 0,<br \/>\nWSB_STREAM_ENCRYPTION_METHOD_NULL = 1,<br \/>\nWSB_STREAM_ENCRYPTION_METHOD_AES_128_CBC = 2,<br \/>\nWSB_STREAM_ENCRYPTION_METHOD_AES_128_CTR = 3,<br \/>\nWSB_STREAM_ENCRYPTION_METHOD_DVB_CSA   = 4<br \/>\n} WSB_StreamEncryptionMethod;<\/p>\n<p>typedef struct WSB_AudioMediaInfo {<br \/>\nWSB_UInt32 channel_count;<br \/>\nWSB_UInt32 sample_rate;<br \/>\nWSB_UInt32 sample_size;<br \/>\n} WSB_AudioMediaInfo;<\/p>\n<p>typedef struct WSB_VideoMediaInfo {<br \/>\nWSB_UInt32 width;<br \/>\nWSB_UInt32 height;<br \/>\nWSB_UInt32 depth;<br \/>\n} WSB_VideoMediaInfo;<\/code>\n<\/div>\n<h3>Track-Related Methods<\/h3>\n<p>Call WSB_MediaFile_GetTrackCount to find out the number of tracks in the media file. To obtain information about a particular track, call WSB_MediaFile_GetTrackInfo. This method returns a WSB_TrackInfo object whose methods can be called to obtain various types ofinformation about the track. <\/p>\n<h3>License-Related Methods<\/h3>\n<p>If the license corresponding to the content in the file is embedded in the file, WSB_MediaFile_GetLicense returns the embedded license. If you have a license that you want embedded within a media file, call<\/p>\n<p>WSB_MediaFile_SetLicense.<\/p>\n<p>WSB_MediaFile_GetRightsIssuerUrls returns the rights issuer URLs corresponding to each content ID in a specified media file. You pass it a pointer to the relevant WSB_MediaFile, and the address of a SHI_Attribute pointer. This pointer is set to NULL if no rights issuer URLs are found. Otherwise, this method creates a SHI_Attribute of type<\/p>\n<p>SHI_ATTRIBUTE_TYPE_LIST, and sets the passed-in SHI_Attribute pointer to refer to this SHI_Attribute. The names of the children in the list are content IDs, and for each, the value is of type SHI_ATTRIBUTE_TYPE_STRING and it contains the rights issuer URL associated with that content ID. The caller is responsible for releasing the SHI_Attribute when no longer needed (the children will automatically be released) by calling SHI_Attribute_Release. WSB_MediaFile_GetSilentLicenseAcquisitionUrls returns the silent license acquisition URLs contained in the media file, which are used as needed (e.g., by the Wasabi Rights Enabler)  to attempt to obtain the license corresponding to the content in the file, if the license is not embedded within the file. Pass this method a pointer to the relevant WSB_MediaFile, and the address of a SHI_Attribute pointer. This pointer is set to NULL if no silent license acquisition URLs are found.<\/p>\n<p>Otherwise, this method creates a SHI_Attribute of type SHI_ATTRIBUTE_TYPE_LIST, and sets the passed-in SHI_Attribute pointer to refer to this SHI_Attribute. The names of the children in the list are content IDs, and for each, the value is of type SHI_ATTRIBUTE_TYPE_STRING and it contains the silent license acquisition URL associated with that content ID. The caller is responsible for releasing the SHI_Attribute when no longer needed (the children will automatically be released) by calling SHI_Attribute_Release.<\/p>\n<h4>Releasing the WSB_MediaFile<\/h4>\n<p>When you no longer need a WSB_MediaFile object, close the media file it references and release the WSB_MediaFile by calling WSB_MediaFile_Close.<\/p>\n<h3>WSB_TrackInfo Methods<\/h3>\n<p>A WSB_TrackInfo object represents information about a track in a media file.<\/p>\n<h3>Obtaining WSB_TrackInfo Objects<\/h3>\n<p>WSB_TrackInfo objects are created as a result of calls to WSB_MediaFile_GetTrackInfo. You pass that method a WSB_MediaFile representing the file whose track information you want to obtain, and a 0-based index indicating the number of the track whose information you want.<\/p>\n<h3>WSB_TrackInfo Methods<\/h3>\n<p>Once you have a WSB_TrackInfo object, you can call WSB_TrackInfo_GetTrackId to obtain the track ID, and WSB_TrackInfo_GetContentId to obtain the content ID.<\/p>\n<p>If you call WSB_TrackInfo_GetMediaInfo, and pass it a pointer to a WSB_MediaInfo structure, it will fill in the structure with the following information:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef struct WSB_MediaInfo {<br \/>\nWSB_MediaType type;<br \/>\nWSB_MediaFormat format;<br \/>\nWSB_UInt32 duration; \/**&lt; in ms *\/<br \/>\nWSB_UInt32 bitrate; \/**&lt; in bits\/sec *\/<br \/>\nWSB_StreamEncryptionMethod encryption_method;<br \/>\nunion {<br \/>\nWSB_AudioMediaInfo audio;<br \/>\nWSB_VideoMediaInfo video;<br \/>\n} specific;<br \/>\n} WSB_MediaInfo;<\/code>\n<\/div>\n<p>When you no longer need a WSB_TrackInfo, release it by calling WSB_TrackInfo_Release.<\/p>\n<h3>Media File-related Data Types<\/h3>\n<p>The enums and structures utilized by WSB_MediaFile and WSB_TrackInfo objects are the following:<\/p>\n<p>WSB_ AudioMediaInfo Information about audio media<\/p>\n<p>WSB_FileProgress Information about the total number of bytes in a file, and the number that are currently available, e.g., while a download is in progress<\/p>\n<p>WSB_MediaFileProtectionType Identifiers for media file protection types<\/p>\n<p>WSB_MediaFormat Identifiers for media formats<\/p>\n<p>WSB_MediaInfo Comprehensive information about amedia file, including the WSB_MediaType, WSB_MediaFormat, etc.<\/p>\n<p>WSB_MediaType Identifiers for the different media types<\/p>\n<p>WSB_StreamEncryptionMethod Identifiers for stream encryption methods<\/p>\n<p>WSB_VideoMediaInfo Information about video media<\/p>\n<\/div>\n<p><!-- wsb_mediafileandwsb_trackinfo--><\/p>\n<div id=\"wsb_playbackenabler\">\n<h2>WSB_PlaybackEnabler<\/h2>\n<p>A WSB_PlaybackEnabler object can be used to do everything possible to obtain a valid license for a given WSB_MediaFile object or for content with a specified content ID (using an internal WSB_RightsEnabler object) and then exercise this license and populate a WSB_KeyManager object with the content keys.<\/p>\n<h3>Creating a WSB_PlaybackEnabler and Registering a Callback Listener<\/h3>\n<p>A WSB_PlaybackEnabler object is created by calling WSB_PlaybackEnabler_Create. You pass this method the address of a WSB_PlaybackEnabler pointer that is set to refer to the WSB_PlaybackEnabler object that the method creates. You also pass it a \u201clistener\u201d that is optionally notified of events occurring while the WSB_PlaybackEnabler_EnableMediaFile or<br \/>\nWSB_PlaybackEnabler_EnableContentId method (see below) is looking for a valid license. If<br \/>\nthe listener\u2019s handler method pointer is not NULL, the handler method is called for each<br \/>\nevent, and its event argument specifies the type of event and supplies event information. The<br \/>\nlistener is a WSB_RightsEnabler_EventListener which,  is defined as follows:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef struct {<br \/>\nvoid* instance;<br \/>\nWSB_RightsEnabler_ContinuationType<br \/>\n(*handler)(void* instance,<br \/>\nconst WSB_RightsEnabler_Event* event);<br \/>\n} WSB_RightsEnabler_EventListener;<\/code>\n<\/div>\n<p>As an example, if the event type is WSB_RIGHTSENABLER_EVENT_TYPE_LICENSE, the event data structure<br \/>\nis a WSB_RightsEnabler_LicenseEvent, defined as follows:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef struct {<br \/>\nWSB_RightsEnabler_Event base;<br \/>\nWSB_Result processing_result;<br \/>\nconst void* license_data;<br \/>\nWSB_Size license_data_size;<br \/>\nWSB_Boolean is_granted;<br \/>\nSHI_ActionResult* action_result;<br \/>\n} WSB_RightsEnabler_LicenseEvent;<\/code>\n<\/div>\n<p>This event contains the license, an indication of whether the license that was found grants<br \/>\naccess to the content, and a pointer to a SHI_ActionResult containing information about the<br \/>\nlicense requirements, including constraints referred to as obligations and callbacks.<br \/>\nThe processing_result is WSB_SUCCESS if the license was processed correctly,<br \/>\nWSB_ERROR_DRM_BAD_LICENSE_FORMAT if the license format is invalid, or<br \/>\nWSB_ERROR_DRM_CLIENT_SYSTEM_ERROR if the license could not be processed<br \/>\nbecause of a DRM system failure.<\/p>\n<h3>Obtaining a Content URL from an MS3 URL<\/h3>\n<p>MS3 (Marlin Simple Secure Streaming) compound URLs allow a client to retrieve both the<br \/>\ncontent URL and the access rights to the content using the MS3 protocol. All MS3 URLs use the<br \/>\nHTTPS scheme, and thus employ TLS to securely obtain content and rights.<\/p>\n<p>If there is any possibility that the content URL is an MS3 URL, the caller should invoke<br \/>\nWSB_PlaybackEnabler_ResolveUrl. This function returns the URL, unchanged, if it is not<br \/>\nan MS3 URL. Otherwise, it retrieves the access rights (an SAS, Stream Access Statement)<br \/>\nand extract from the compound URL the content URL, and returns the content URL to the<br \/>\ncaller. The application can then proceed with enabling the media file or content, as described in<br \/>\nthe next section. Regardless of whether or not the suppled URL is an MS3 URL, a content URL<br \/>\nis returned, so the caller can use this value in any case. The return value is a SHI_Data<br \/>\nobject, of type SHI_DATA_TYPE_STRING. The content URL should be freed by the caller when<br \/>\nno longer needed by calling SHI_Data_Release.<\/p>\n<p>The WSB_PlaybackEnabler API does not otherwise handle content URLs.<br \/>\nIn the case of a media file or stream that is Marlin-defined, the content URL returned by this API<br \/>\nshould be passed to WSB_MediaFile_Open  in order to open the specified content file and<br \/>\ncreate a WSB_MediaFile object referencing it that can be passed to<br \/>\nWSB_PlaybackEnabler_EnableMediaFile.<\/p>\n<h3>Obtaining a Valid License<\/h3>\n<p>Two different methods can be called to try to obtain a working license for content. Call<br \/>\nWSB_PlaybackEnabler_EnableMediaFile if you can obtain a WSB_MediaFile  referencing<br \/>\na media file or stream whose format is Marlin-defined\u2014and thus Wasabi knows how to process<br \/>\nit, for example to extract an embedded license or silent license acquisition URL, if any. Call<br \/>\nWSB_PlaybackEnabler_EnableContentId when you cannot obtain such a WSB_MediaFile,<br \/>\nbut a license or MS3 SAS may grant access to content with a specified ID. It is useful, for<br \/>\nexample, for situations where the content ID changes during streaming. It is also useful in<br \/>\nsituations where a license grants access to content in a media file whose format is not Marlin defined.<br \/>\nIn this case, an application can use this method to find such a license and can<br \/>\nsubsequently use the Wasabi Key Manager to obtain the content key(s) from the license.<\/p>\n<p>For either method, if you actually already have a license for the content, and you want the<br \/>\nmethod to check whether that license is currently valid, then you can optionally also pass the<br \/>\nlicense bytes and a value indicating the number of bytes.<\/p>\n<p>WSB_PlaybackEnabler_EnableMediaFile calls WSB_MediaFile and WSB_TrackInfo<br \/>\nmethods to obtain the content IDs and track IDs (if it is a type of file that has tracks) for the<br \/>\nmedia file. If no errors occur, it then calls WSB_RightsEnabler_EnableMediaFile, which performs a number of steps to do everything possible to try to find a currently valid license.<\/p>\n<p>WSB_PlaybackEnabler_EnableContentId calls WSB_RightsEnabler_EnableContentId.<\/p>\n<p>Prior to calling either of those methods, you can optionally call<br \/>\nWSB_PlaybackEnabler_SetRightsEnablerOptions to set option flags controlling<br \/>\nWSB_RightsEnabler_EnableMediaFile behavior. By default, all flags are off. The possible flags,<br \/>\ndefined in WsbRightsEnabler.h, are named the following:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>WSB_RIGHTSENABLER_OPTION_FLAG_DISABLE_SLA<br \/>\nWSB_RIGHTSENABLER_OPTION_FLAG_DISABLE_LINK_RENEWAL<br \/>\nWSB_RIGHTSENABLER_OPTION_FLAG_DISABLE_STORING_LICENSE_IN_FILE<\/code>\n<\/div>\n<p>Each of these flags disables a particular potential action normally taken by<br \/>\nWSB_RightsEnabler_EnableMediaFile or WSB_RightsEnabler_EnableContentId.<\/p>\n<p>Whenever WSB_RightsEnabler_EnableMediaFile or WSB_RightsEnabler_EnableContentId<br \/>\nfinds a license, the license is supplied to the Playback Enabler in an event of type<br \/>\nWSB_RIGHTSENABLER_EVENT_TYPE_LICENSE. The Playback Enabler stores the license<br \/>\ndata and also forwards the event to the client listener passed in the call to<br \/>\nWSB_PlaybackEnabler_Create, if the listener handler method pointer is not NULL. This case<br \/>\nis described first, followed by information regarding what happens if it is NULL.<\/p>\n<p>The listener should determine whether it is satisfied with the specified license (in which case, it<br \/>\nreturns WSB_RIGHTSENABLER_HALT_SEARCH) or would prefer to have the search continue<br \/>\nfor another license (in which case, it returns WSB_RIGHTSENABLER_CONTINUE_SEARCH).<\/p>\n<p>In order to examine the license, it is common to call WSB_Config_ValidateActionResult. If the Play action is granted and all mandatory obligations and callbacks can be satisfied,<br \/>\nWSB_Config_ValidateActionResult returns WSB_SUCCESS. If the action is not granted, it<br \/>\nreturns WSB_ERROR_DRM_DENY_RIGHTS, and it returns<br \/>\nWSB_ERROR_DRM_LICENSE_UNSUPPORTED if there are mandatory callbacks or<br \/>\nobligations that cannot be satisfied.<\/p>\n<p>If the action is not granted, you can call WSB_ExplainActionResultFailure to obtain an<br \/>\nerror code with a more explicit explanation as to why the action is not granted (such as the<br \/>\nlicense having expired).<\/p>\n<p>Here is an example of how a listener handler method might handle a license event:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>static WSB_RightsEnabler_ContinuationType<br \/>\nOnEnablerEvent(void* instance, const WSB_RightsEnabler_Event* event)<br \/>\n{<br \/>\nWSB_Result result;<br \/>\n\/\/ we're only interested in license data<br \/>\nif (event-&gt;type == WSB_RIGHTSENABLER_EVENT_TYPE_LICENSE) {<br \/>\nWSB_RightsEnabler_LicenseEvent* license_event =<br \/>\n(WSB_RightsEnabler_LicenseEvent*)event;<br \/>\nif (WSB_FAILED(license_event-&gt;processing_result)) {<br \/>\n\/\/ license just could not be processed; handle this case<br \/>\n. . .;<br \/>\n} else {<br \/>\nresult = WSB_Config_ValidateActionResult(<br \/>\nlicense_event-&gt;action_result,<br \/>\nWSB_FALSE,<br \/>\nSHI_ACTION_PLAY,<br \/>\nNULL);<br \/>\nif (WSB_SUCCEEDED(result)) {<br \/>\n\/\/ we've found a valid license!<br \/>\nreturn WSB_RIGHTSENABLER_HALT_SEARCH;<br \/>\n} else if (result == WSB_ERROR_DRM_DENY_RIGHTS) {<br \/>\n\/\/ play action not granted, get more information<br \/>\nSHI_Data* goto_url_data = NULL;<br \/>\nresult = WSB_ExplainActionResultFailure(<br \/>\nlicense_event-&gt;action_result,<br \/>\nNULL,<br \/>\nmedia_file,<br \/>\n&amp;goto_url_data);<br \/>\n\/* if desired, save or further process this result *\/<br \/>\n. . .<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\nreturn WSB_RIGHTSENABLER_CONTINUE_SEARCH;<br \/>\n}<\/code>\n<\/div>\n<p>If the listener <code>handler<\/code> method is NULL, then when a license is supplied to the Playback<br \/>\nEnabler, the Playback Enabler does the same things as the client listener would typically do<br \/>\n(described above), except that it always returns WSB_RIGHTSENABLER_HALT_SEARCH if<br \/>\nWSB_Config_ValidateActionResult returns WSB_SUCCESS. In other words, the default<br \/>\nbehavior is that the Playback Enabler always stops the search as soon as any valid license is<br \/>\nfound.<\/p>\n<p>In the case of MS3 content, the WSB_PlaybackEnabler_EnableMediaFile or<br \/>\nWSB_PlaybackEnabler_EnableContentId method should still be invoked, and a NULL<br \/>\nlicense_data parameter should be supplied. The rights acquired during the call to<br \/>\nWSB_PlaybackEnabler_ResolveURL is used to enable the media file.<\/p>\n<h3>Checking the License and Obtaining Keys<\/h3>\n<p>At any point after calling WSB_PlaybackEnabler_EnableMediaFile or<br \/>\nWSB_PlaybackEnabler_EnableContentId, and prior to attempting content playback, call<br \/>\nWSB_PlaybackEnabler_PerformPlayAction to perform the \u201cPlay\u201d action on the license (or, in<br \/>\nthe case of MS3 content, the access rights). Essentially, this determines whether the Play action<br \/>\nis currently allowed, and creates a SHI_ActionResult containing information about what is<br \/>\nallowed and what is required. WSB_PlaybackEnabler_PerformPlayAction does not actually play<br \/>\nthe content, but it must be executed as one of the steps prior to playing the content. Pass this<br \/>\nmethod the address of a SHI_ActionResult pointer that will be set to refer to the<br \/>\nSHI_ActionResult object created by this call. A WSB_Result of WSB_SUCCESS does not mean<br \/>\nthat the Play action is granted. The SHI_ActionResult returned by the call must be analyzed to<br \/>\ndetermine that, as described in the following.<\/p>\n<p>The SHI_ActionResult should be analyzed by calling WSB_Config_ValidateActionResult. As<br \/>\nstated above, this method is responsible for analyzing the SHI_ActionResult to determine<br \/>\nwhether the Play action is granted, and whether all of the mandatory obligations and callbacks<br \/>\n(if any) can be satisfied.<\/p>\n<p>WSB_Config_ValidateActionResult returns WSB_SUCCESS if the application should be<br \/>\nallowed access to the protected content. In this case, call WSB_KeyManager_Create to<br \/>\ninstantiate a WSB_KeyManager object, and then call<br \/>\nWSB_PlaybackEnabler_AcceptActionResult, passing it the WSB_KeyManager. This method<br \/>\nobtains the content keys and supply them to the WSB_KeyManager. This method also has<br \/>\nan optional parameter specifying the address of a SHI_Action pointer which, if specified, is<br \/>\nset to refer to the internal SHI_Action object, which may be needed for exercising callbacks. The<br \/>\ncaller does not take ownership, and therefore must not destroy this SHI_Action.<\/p>\n<h3>Destroying the WSB_PlaybackEnabler<\/h3>\n<p>When the WSB_PlaybackEnabler object is no longer needed, destroy it by calling<br \/>\nWSB_PlaybackEnabler_Destroy.<\/p>\n<\/div>\n<p><!-- wsb_playbackenabler--><\/p>\n<div id=\"wsb_proxymanager\">\n<h2>WSB_ProxyManager<\/h2>\n<p>A WSB_ProxyManager object can be used to set global (per application) proxies for HTTP and HTTPS transactions.<\/p>\n<p>Call WSB_ProxyManager_SetHttpProxy to set the proxy to be used for HTTP transactions. You pass it the hostname and port.<\/p>\n<p>Call WSB_ProxyManager_SetHttpsProxy to set the proxy to be used for HTTPS transactions. As with WSB_ProxyManager_SetHttpProxy, you pass the hostname and port to be used.<\/p>\n<p>Here is how proxy selection works in ExpressPlay SDK:<\/p>\n<ul>\n<li>If the proxies have been set using the WSB_ProxyManager methods, then those proxies are utilized.<\/li>\n<li>For convenience in testing and in running sample applications (not for running applications in production environments), it is possible to use a proxy without modifying the code to call the WSB_ProxyManager methods. If proxies are not set, as described above, or are unusable (e.g., set to an empty string), ExpressPlay SDK checks the values of certain environment variables, as described in the following, to try to determine what proxies to use, if any.<\/li>\n<li>An environment variable named NEPTUNE_NET_CONFIG_PROXY_SELECTOR can have 3 values. If it is set to no proxy (or the variable does not exist), then no proxy is used. If it is set to system, then that indicates that the system\u2019s default proxies (if set) should be used. If it is set to env, then the proxy set in the http_proxy environment variable is used for HTTP transactions, and the proxy set in the https_proxy environment variable is used for HTTPS transactions.<\/li>\n<li>However, there are two other environment variables whose values affect which proxy is actually used, and even whether a proxy is used. The NO_PROXY environment variable contains a comma-separated list of hosts for which no proxy should be used. If it has the special value of \u201c*\u201d, then no proxies are used for any hosts. The environment variable named ALL_PROXY specifies the proxy that should be used if the proxy hostname set in http_proxy or https_proxy is invalid.<\/li>\n<\/ul>\n<p>Please note that http_proxy must be all lowercase, but https_proxy, no_proxy, and all_proxy can each be either all lowercase or all uppercase.<\/p>\n<\/div>\n<p><!-- wsb_proxymanager--><\/p>\n<div id=\"wsb_rightsenabler\">\n<h2>WSB_RightsEnabler<\/h2>\n<p>A WSB_RightsEnabler object can be used to have everything possible done to obtain a license<br \/>\ngranting access to specified content. A WSB_RightsEnabler object is created and utilized<br \/>\ninternally as needed by other Wasabi classes, such as WSB_PlaybackEnabler, and the<br \/>\nRights Enabler functionality is also available to external applications via the<br \/>\nWSB_RightsEnabler methods.<\/p>\n<h3>Creating a WSB_RightsEnabler Object<\/h3>\n<p>A WSB_RightsEnabler object is created by calling WSB_RightsEnabler_Create. You pass it<br \/>\nthe address of a WSB_RightsEnabler pointer that is set by this method to refer to the<br \/>\nWSB_RightsEnabler object that the method creates. You also pass it a \u201clistener\u201d that is<br \/>\nnotified of events occurring while the WSB_RightsEnabler_EnableMediaFile or<br \/>\nWSB_RightsEnabler_EnableContentId method (see below) is looking for a valid license. The<br \/>\nlistener\u2019s handler method is called for each event, and its event argument specifies the<br \/>\ntype of event and supplies event information, as discussed below under \u201cEvent Structures.\u201d The<br \/>\nlistener has the following type:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef struct {<br \/>\nvoid* instance;<br \/>\nWSB_RightsEnabler_ContinuationType<br \/>\n(*handler)(void* instance,<br \/>\nconst WSB_RightsEnabler_Event* event);<br \/>\n} WSB_RightsEnabler_EventListener<\/code>\n<\/div>\n<p>The handler return value is of the following type:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef enum {<br \/>\nWSB_RIGHTSENABLER_HALT_SEARCH,<br \/>\nWSB_RIGHTSENABLER_CONTINUE_SEARCH<br \/>\n} WSB_RightsEnabler_ContinuationType;<\/code>\n<\/div>\n<p>The return value is primarily relevant for license events. When such an event occurs, indicating<br \/>\nthat a license was found, the handler can decide whether it wants the Rights Enabler to stop<br \/>\nlooking or to continue the search for a different license (as discussed further below), and the<br \/>\nhandler indicates its choice by the appropriate return value. For other events, the return value is<br \/>\nconsidered more of a request, and a request to halt may or may not be satisfied due to internal<br \/>\nreasons.<\/p>\n<h3>Event Structures<\/h3>\n<p>WSB_RightsEnabler_Event is the base class for all event structures. It is defined as follows:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef struct {<br \/>\nWSB_RightsEnabler_EventType type;<br \/>\n} WSB_RightsEnabler_Event;<\/code>\n<\/div>\n<p>The types of events that may be reported to the listener are the following:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef enum {<br \/>\nWSB_RIGHTSENABLER_EVENT_TYPE_GOTO_URL,<br \/>\nWSB_RIGHTSENABLER_EVENT_TYPE_TRANSACTION,<br \/>\nWSB_RIGHTSENABLER_EVENT_TYPE_LICENSE<br \/>\n} WSB_RightsEnabler_EventType;<\/code>\n<\/div>\n<p>When the listener is called, it is passed a pointer to a WSB_RightsEnabler_Event. A more<br \/>\ndetailed structure, with WSB_RightsEnabler_Event as the base, is actually passed to the<br \/>\nlistener, and this structure depends on the event type. The event pointer should be cast to the<br \/>\nappropriate data structure type. The data structures to which events of various types should be<br \/>\ncast are the following:<\/p>\n<table >\n<tbody>\n<tr>\n<td class=\"\"><b>Event Type <\/b><\/td>\n<td class=\"\"><b>Data Structure<\/b><\/td>\n<\/tr>\n<tr>\n<td class=\"\"><code class=\"\">WSB_RIGHTSENABLER_EVENT_TYPE_<br \/>\nGOTO_URL <\/code><\/td>\n<td class=\"\"><code class=\"\">WSB_RightsEnabler_GotoURLEvent<\/code><\/td>\n<\/tr>\n<tr>\n<td class=\"\"><code class=\"\">WSB_RIGHTSENABLER_EVENT_TYPE_<br \/>\nLICENSE<\/code><\/td>\n<td class=\"\"><code class=\"\">WSB_RightsEnabler_LicenseEvent<\/code><\/td>\n<\/tr>\n<tr>\n<td class=\"\"><code class=\"\">WSB_RIGHTSENABLER_EVENT_TYPE_<br \/>\nTRANSACTION<\/code><\/td>\n<td class=\"\"><code class=\"\">WSB_RightsEnabler_TransactionEvent<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><\/p>\n<p>If the Rights Enabler has been directed to a service for obtaining needed rights, the<br \/>\nWSB_RightsEnabler_GotoURLEvent reports this fact and specifies the URL that the Rights<br \/>\nEnabler was directed to.<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef struct {<br \/>\nWSB_RightsEnabler_Event base;<br \/>\nconst char* url;<br \/>\n} WSB_RightsEnabler_GotoURLEvent;<\/code>\n<\/div>\n<p>Whenever the Rights Enabler finds a license, it calls the listener with a WSB_RightsEnabler_LicenseEvent:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef struct {<br \/>\nWSB_RightsEnabler_Event base;<br \/>\nWSB_Result processing_result;<br \/>\nconst void* license_data;<br \/>\nWSB_Size license_data_size;<br \/>\nWSB_Boolean is_granted;<br \/>\nSHI_ActionResult* action_result;<br \/>\n} WSB_RightsEnabler_LicenseEvent;<\/code>\n<\/div>\n<p>This event contains the license, an indication of whether the license that was found grants<br \/>\naccess to the content, and a pointer to a SHI_ActionResult that contains information about the<br \/>\nlicense requirements, including constraints referred to as obligations and callbacks. The<br \/>\nprocessing_result is WSB_SUCCESS if the license was processed correctly,<br \/>\nWSB_ERROR_DRM_BAD_LICENSE_FORMAT if the license format is invalid, or<br \/>\nWSB_ERROR_DRM_CLIENT_SYSTEM_ERROR if the license could not be processed<br \/>\nbecause of a DRM system failure.<\/p>\n<p>When the listener receives an event of this type, it should decide whether it is satisfied with the<br \/>\nspecified license or would prefer to have the Rights Enabler continue its search for another<br \/>\nlicense. In the former case, the listener handler method should return<br \/>\nWSB_RIGHTSENABLER_HALT_SEARCH. Otherwise it should return<br \/>\nWSB_RIGHTSENABLER_CONTINUE_SEARCH. In order to determine whether or not to<br \/>\ncontinue the search, or simply to get information about the license requirements, the listener<br \/>\nmay want to analyze the SHI_ActionResult. It can do so, for example, by calling<br \/>\nWSB_Config_ValidateActionResult to determine whether content playback is allowed and<br \/>\nwhether all of the mandatory obligations and callbacks (if any) can be satisfied.<\/p>\n<p>A WSB_RightsEnabler_TransactionEvent indicates that a service transaction (link renewal or<br \/>\nsilent license acquisition) has been initiated in an attempt to obtain rights.<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>typedef struct {<br \/>\nWSB_RightsEnabler_Event base;<br \/>\nWSB_RightsEnabler_TransactionType transaction_type;<br \/>\n} WSB_RightsEnabler_TransactionEvent;<\/code>\n<\/div>\n<h3>Obtaining a Valid License<\/h3>\n<p>The purpose of the WSB_RightsEnabler object is to try everything possible to obtain a working<br \/>\nlicense for content with one or more specified IDs. Call WSB_RightsEnabler_EnableMediaFile<br \/>\nor WSB_RightsEnabler_EnableContentId to invoke this functionality. The former is called<br \/>\nwhen you can create a WSB_MediaFile referencing a media file or stream whose format is<br \/>\nMarlin-defined\u2014and thus Wasabi knows how to process it, for example to extract an embedded<br \/>\nlicense or silent license acquisition URL, if any. The latter is called when you cannot create such<br \/>\na WSB_MediaFile. It is useful, for example, for situations where the content ID changes during<br \/>\nstreaming. It is also useful in situations where a license grants access to content in a media file<br \/>\nwhose format is not Marlin-defined.<\/p>\n<p>First, prior to calling either of those methods, you can optionally call WSB_RightsEnabler_SetOptions to set option flags controlling their behavior, disabling one or more actions normally taken (which are described below). By default, all flags are off. The flags that can be set are the following:<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>WSB_RIGHTSENABLER_OPTION_FLAG_DISABLE_SLA<\/code>\n<\/div>\n<p>If this flag is set, no silent license acquisitions are attempted.<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>WSB_RIGHTSENABLER_OPTION_FLAG_DISABLE_LINK_RENEWAL<\/code>\n<\/div>\n<p>If this flag is set, no subscription links are renewed.<\/p>\n<div class=\"bg-grey-100 p-8 mb-12 mt-12\">\n<code>WSB_RIGHTSENABLER_OPTION_FLAG_DISABLE_STORING_LICENSE_IN_FILE<\/code>\n<\/div>\n<p>If this flag is set, WSB_RightsEnabler_EnableMediaFile does not attempt to write a valid<br \/>\nlicense to the media file.<\/p>\n<h3>WSB_RightsEnabler_EnableMediaFile<\/h3>\n<p>Prior to calling WSB_RightsEnabler_EnableMediaFile, you create a WSB_MediaFile referencing<br \/>\nthe media file or stream whose content you want to find a license for, and you obtain from that<br \/>\nmedia file\/stream the content ID(s). You then pass WSB_RightsEnabler_EnableMediaFile the WSB_MediaFile, an array of the content IDs, and a number indicating how many content IDs are in the array. If you actually already have a license<br \/>\nfor the content, and you want this method to check whether that license is currently valid, then<br \/>\nyou can optionally also pass the license bytes and a value indicating the number of bytes.<\/p>\n<p>WSB_RightsEnabler_EnableMediaFile performs the steps below, in order, in an attempt to find<br \/>\na license for the content with the specified content IDs. For each license it finds, it returns the<br \/>\nlicense to the caller in a WSB_RightsEnabler_LicenseEvent structure passed to the listener<br \/>\nregistered in the call to WSB_RightsEnabler_Create. In that event structure, the Rights Enabler<br \/>\nalso provides the information as to whether or not the license grants access, and supplies the<br \/>\nSHI_ActionResult containing further information about the license requirements, as discussed in<br \/>\nthe previous section. The listener returns to the Rights Enabler a<br \/>\nWSB_RightsEnabler_ContinuationType value instructing the Rights Enabler whether to halt the<br \/>\nsearch or to continue searching for another license. If the latter, the Rights Enabler continues<br \/>\nthe search steps shown below. Otherwise, the search is stopped.<\/p>\n<p style=\"word-wrap: break-word;\">If the most recent license found before the search was halted is a valid one, and<br \/>\nWSB_RIGHTSENABLER_OPTION_FLAG_DISABLE_STORING_LICENSE_IN_FILE is not set,<br \/>\nWSB_RightsEnabler_EnableMediaFile then tries to write the license to the media file, if it is not<br \/>\nalready embedded within that media file. If WSB_RightsEnabler_EnableMediaFile cannot<br \/>\nembed the license within the media file, or the specified option is set,<br \/>\nWSB_RightsEnabler_EnableMediaFile stores the license in the Wasabi License Store. In<br \/>\nany case, it then returns to the caller.<\/p>\n<p>Here are the steps WSB_RightsEnabler_EnableMediaFile performs to try to find a currently<br \/>\nvalid license:<\/p>\n<ol>\n<li>Check the license that was passed in (if any).<\/li>\n<li>Check the license embedded in the media file (if any).<\/li>\n<li>Check the License Store to see whether it contains a license for the content.<\/li>\n<li style=\"word-wrap: break-word;\">If WSB_RIGHTSENABLER_OPTION_FLAG_DISABLE_LINK_RENEWAL is not set, try<br \/>\nautomatic renewal of the subscription (if any) to the content, and recheck all of the<br \/>\nlicenses found up to this point\u2014the passed-in license, the embedded license, or a<br \/>\nlicense in the License Store, in that order.<\/li>\n<li style=\"word-wrap: break-word;\">If the media file\/stream has a silent license acquisition header, and<br \/>\nWSB_RIGHTSENABLER_OPTION_FLAG_DISABLE_SLA is not set, then use the specified<br \/>\nURL to attempt to automatically acquire a license. Check whether the returned license is<br \/>\nvalid. If not, try updating the subscription referenced by the license (if any) and then<br \/>\ncheck (and report in a license event) the license again.<\/li>\n<\/ol>\n<p>Please note: During WSB_RightsEnabler_EnableMediaFile execution, control programs that<br \/>\ngovern access to content will be executed. There is a limit of 40 million execution steps allowed,<br \/>\nand if that number is reached (which would only happen if there was a control program bug<br \/>\nresulting in an infinite loop), WSB_RightsEnabler_EnableMediaFile returns<br \/>\nWSB_ERROR_DRM_DENY_RIGHTS.<\/p>\n<h4>WSB_RightsEnabler_EnableContentId<\/h4>\n<p>WSB_RightsEnabler_EnableContentId essentially performs the same actions as<br \/>\nWSB_RightsEnabler_EnableMediaFile to find a license, except that in this case, there is no<br \/>\nWSB_MediaFile, therefore, no media file-related actions are performed by the method. As with<br \/>\nWSB_RightsEnabler_EnableMediaFile, WSB_RightsEnabler_EnableContentId returns each<br \/>\nlicense it finds to the caller in a WSB_RightsEnabler_LicenseEvent structure passed to the<br \/>\nlistener registered in the call to WSB_RightsEnabler_Create.<\/p>\n<p>Here are the steps taken by WSB_RightsEnabler_EnableContentId to try to find a valid license:<\/p>\n<ol>\n<li>Check the license that was passed in (if any).<\/li>\n<li>Check the License Store to see whether it contains a license for the content.<\/li>\n<li style=\"word-wrap: break-word;\">If WSB_RIGHTSENABLER_OPTION_FLAG_DISABLE_LINK_RENEWAL is not set, try<br \/>\nautomatic renewal of the subscription (if any) to the content, and recheck all of the<br \/>\nlicenses found up to this point\u2014the passed-in license or a license in the License Store,<br \/>\nin that order.<\/li>\n<li style=\"word-wrap: break-word;\">If a silent license acquisition URL was passed in the call, and<br \/>\nWSB_RIGHTSENABLER_OPTION_FLAG_DISABLE_SLA is not set, then use the specified<br \/>\nURL to attempt to automatically acquire a license. Check whether the returned license is<br \/>\nvalid. If not, try updating the subscription referenced by the license (if any) and then<br \/>\ncheck (and report in a license event) the license again.<\/li>\n<\/ol>\n<h3>Destroying the WSB_RightsEnabler<\/h3>\n<p>When the WSB_RightsEnabler object is no longer needed, destroy it by calling<br \/>\nWSB_RightsEnabler_Destroy.<\/p>\n<h3>Rights Enabler-related Data Types<\/h3>\n<p>The enums and structures utilized by WSB_RightsEnabler objects are the following:<\/p>\n<table class=\"table-bordered boxslice3 sdk-table\" style=\"padding: 6px;\">\n<tbody>\n<tr>\n<td class=\"\"><code class=\"\">WSB_RightsEnabler_Event<\/code><\/td>\n<td class=\"\">Base structure for all event structures<\/td>\n<\/tr>\n<tr>\n<td class=\"\"><code class=\"\">WSB_RightsEnabler_EventListener<\/code><\/td>\n<td class=\"\">Structure pairing a listener instance value<br \/>\nwith a function pointer for receiving events<\/td>\n<\/tr>\n<tr>\n<td class=\"\"><code class=\"\">WSB_RightsEnabler_EventType<\/code><\/td>\n<td class=\"\">Identifiers for event types<\/td>\n<\/tr>\n<tr>\n<td class=\"\"><code class=\"\">WSB_RightsEnabler_GotoURLEvent<\/code><\/td>\n<td class=\"\">Event data for reporting that the Rights<br \/>\nEnabler has been directed to a service for obtaining the license<\/td>\n<\/tr>\n<tr>\n<td class=\"\"><code class=\"\">SB_RightsEnabler_LicenseEvent<\/code><\/td>\n<td class=\"\">Event data for reporting a valid license<br \/>\nthat was found<\/td>\n<\/tr>\n<tr>\n<td class=\"\"><code class=\"\">WSB_RightsEnabler_TransactionEvent<\/code><\/td>\n<td class=\"\">Event data for reporting that a data<br \/>\nservice transaction has been initiated in an attempt to obtain the needed rights<\/td>\n<\/tr>\n<tr>\n<td class=\"\"><code class=\"\">WSB_RightsEnabler_TransactionType<\/code><\/td>\n<td class=\"\">Identifiers for transactions<\/td>\n<\/tr>\n<\/tbody>\n<\/table>","protected":false},"excerpt":{"rendered":"<p>Source SDK Development Guide Jump to section What the SDK Can Do What Are the Steps to Play What Are the Steps for eBooks Key Concepts SDK Usage Guidelines Personalization Content License Acquisition Media Playback MediaStream for eBooks Other DRM Functions Selected Classes for Embedded Development What the SDK can do The ExpressPlay Source SDK [&hellip;]<\/p>\n","protected":false},"author":124,"featured_media":0,"parent":10924,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"page-expressplay-developer.php","meta":{"_acf_changed":false,"footnotes":""},"tax_page_type":[512],"coauthors":[621],"class_list":["post-11074","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.expressplay.com\/ko\/wp-json\/wp\/v2\/pages\/11074","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.expressplay.com\/ko\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.expressplay.com\/ko\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.expressplay.com\/ko\/wp-json\/wp\/v2\/users\/124"}],"replies":[{"embeddable":true,"href":"https:\/\/www.expressplay.com\/ko\/wp-json\/wp\/v2\/comments?post=11074"}],"version-history":[{"count":0,"href":"https:\/\/www.expressplay.com\/ko\/wp-json\/wp\/v2\/pages\/11074\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/www.expressplay.com\/ko\/wp-json\/wp\/v2\/pages\/10924"}],"wp:attachment":[{"href":"https:\/\/www.expressplay.com\/ko\/wp-json\/wp\/v2\/media?parent=11074"}],"wp:term":[{"taxonomy":"tax_page_type","embeddable":true,"href":"https:\/\/www.expressplay.com\/ko\/wp-json\/wp\/v2\/tax_page_type?post=11074"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.expressplay.com\/ko\/wp-json\/wp\/v2\/coauthors?post=11074"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}