<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Windows CE Multimedia Team Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/medmedia/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/medmedia/feed.xml</link>
    <description>Multimedia, Graphics, and Audio for Windows CE, Windows Mobile, and their partner products.</description>
    <lastBuildDate>Tue, 16 Apr 2019 05:51:07 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Always think in terms of the current screen orientation</title>
      <link>https://docs.microsoft.com/archive/blogs/medmedia/always-think-in-terms-of-the-current-screen-orientation</link>
      <pubDate>Tue, 08 Jul 2008 00:06:00 GMT</pubDate>
      <dc:creator><![CDATA[yoshihito]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/medmedia/2008/07/08/always-think-in-terms-of-the-current-screen-orientation/</guid>
      <description><![CDATA[Today I am going to write a short development note on a GPE-based display driver for Windows CE as...]]></description>
      <content:encoded><![CDATA[<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">Today I am going to write a short <SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'; mso-fareast-font-family: 'MS Mincho'; mso-fareast-theme-font: minor-fareast; mso-ansi-language: EN-US; mso-fareast-language: JA; mso-bidi-language: AR-SA">development </SPAN>note on a GPE-based display driver for Windows CE as we noticed that this stuff is not clearly documented online and have confused many people including those who are writing display drivers for new platforms at MS. Hopefully this entry might save a few strands of hairs of some people out there somewhere.</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">The topic is about the screen resolutions and orientations supported by the display driver. It is really a simple thing, but there are a set of rules that driver writers must know to get it right. When it is not correctly followed, your device might still boot, but you may start noticing weird glitches here and there.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
<P mce_keep="true">A GPE-based display driver has to override a function called GetModeInfo() which is a pure virtual function defined by the GPE base class. What it does is very simple; It just returns the screen resolution (and some extra information such as bit depth) supported by the device at the given index. It is used in a combination with NumModes() which gives the number of modes that the GetModeInfo() supports. What is important here is that&nbsp;the display driver framework requires that the GetModeInfo() returns the screen resolution relative to the current screen orientation. Not the native screen orientation. Not the boot-time screen orientation. It is always the current screen orientation.</P>
<P mce_keep="true">The screen can take four possible orientations; 0 degree, 90 degrees, 180 degrees, and 270 degrees. Unless you are only dealing with square displays, then depending on the angle, the width and height have to be swapped. For example, if your screen resolution is 800 x 600 at the 0 degree and that is how your GetModeInfo() reports, then it has to return 600 x 800 when the&nbsp;current orientation is at 90 or 270 degrees. Many GWES components that&nbsp;deal with screen resolutions and orientations are dependent upon this behavior, but this doesn't&nbsp;become a problem until you actually try to rotate the screen. So, initially it may look like it is working perfectly, but once you try to rotate it, then you start seeing some&nbsp;issues.</P>
<P mce_keep="true">As far as I can think of off the top of my head, most APIs (if not all) that deal with resolutions such as ChangeDisplaySettingsEx() and SetDisplayMode() all expect&nbsp;resolution parameters to be relative to the current screen orientation. So, the rule of the thumb&nbsp;appears to be this:&nbsp;Always think in terms of the current screen orientation.</P>]]></content:encoded>
    </item>
    <item>
      <title>Keeping your module section count below 16 on Windows CE</title>
      <link>https://docs.microsoft.com/archive/blogs/medmedia/keeping-your-module-section-count-below-16-on-windows-ce</link>
      <pubDate>Fri, 22 Feb 2008 20:13:00 GMT</pubDate>
      <dc:creator><![CDATA[Andy Raffman]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/medmedia/2008/02/22/keeping-your-module-section-count-below-16-on-windows-ce/</guid>
      <description><![CDATA[Here's a quick blog about an issue that we just hit today; most will merely find it interesting, but...]]></description>
      <content:encoded><![CDATA[<P><FONT face=arial,helvetica,sans-serif>Here's a quick blog about an issue that we just hit today; most will merely find it interesting, but I hope it saves someone somewhere a little time, effort, and confusion.</FONT></P>
<P><FONT face=arial,helvetica,sans-serif>We recently got a new codec library drop which we integrated into our mainline code tree. The codec team spends alot of time developing optimized ARM-versions of windows media&nbsp;codecs, and every once in&nbsp;awhile we get a new library&nbsp;that we need to integrate into our build system.</FONT></P>
<P><FONT face=arial,helvetica,sans-serif>When we checked the libary into our source tree&nbsp;and ran a Smartphone build, we got roughly this error from one of our build tools:</FONT></P>
<P><FONT face=arial,helvetica,sans-serif>&nbsp;&nbsp;&nbsp; wmvdmod.dll(0) : fatal error RM0024 : Input File has more than 16 sections</FONT></P>
<P><FONT face=arial,helvetica,sans-serif>In the ensuing investigation we discovered two things we hadn't previously known:</FONT></P>
<P><FONT face=arial,helvetica,sans-serif>1. Our codec team has been subdividing their C/C++/Assembly language routines into multiple sections to keep certain code paths together and improve cache/page hit rates. As a result, they had created about 14 extra sections with names like ".decodeX_Pass1" (names changed to protect the innocent ;-). In general, one can view this type of information for any lib or dll by running "dumpbin -headers" on it.</FONT></P>
<P><FONT face=arial,helvetica,sans-serif>2. Windows CE has some limitations on the number of sections that a module can contain (due to design decisions in the kernel and ROM image filesystems).&nbsp;Ultimately this results in a limit of 16 sections for some scenarios, which is the case we hit in our build tools.</FONT></P>
<P><FONT face=arial,helvetica,sans-serif>The simplest short-term solution to this problem was to use the merge linker directive to force the linker to merge the different sections in the library back into the .text section. To accomplish this, we added something like the following to the appropriate sources file. This solved the build error without the need to rebuild the library (at the expense of removing all the goodness of using multiple sections to control code placement). </FONT></P>
<P><FONT face=arial,helvetica,sans-serif>LDEFINES=$(LDEFINES) \<BR>&nbsp;-merge:.decodeX_Pass1=.text \<BR>&nbsp;-merge:.decodeX_Pass2=.text \<BR>&nbsp;-merge:.decodeY_Pass1=.text \<BR>&nbsp;-merge:.decodeY_Pass2=.text \<BR>...</FONT></P>
<P><FONT face=arial,helvetica,sans-serif>Note: I'm told one can accomplish the same feature within c/cpp files using #pragma comment(linker,"-merge:.foo=.bar")</FONT></P>
<P><FONT face=arial,helvetica,sans-serif>In the ensuing discussion of how to fix this in the correct way (e.g. removing the restriction on the number of sections, or using fewer sections in the codec lib), our compiler/linker guru came down firmly on the side that there's no reason to need more than 16 sections (or really more than four or five), and noted th<FONT color=#000000>at this whole situation could have been easily avoided using the following techniques:</FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"><FONT color=#000000><FONT face=arial,helvetica,sans-serif><FONT size=2>For performance, if you want page alignment, use __declspec(align).&nbsp; If you need to control code layout, use the linker’s /ORDER switch with a file containing the symbol ordering you need.&nbsp; Alternatively, use the linker’s automatic sorting of section suffixes, e.g. .text$FOO_A, .text$FOO_B, and .text$FOO_C are automatically merged with .text in alphabetical order.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></FONT></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=2>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT size=2><FONT face=arial,helvetica,sans-serif>We didn't previously know about the linker options to automatically sort and merge sections using the $ delimiter, and I suspect that most other people don't either. We'll now go back to the codec team and suggest that future drops can just use the automatic sorting mechanism to ensure that code is grouped as needed while keeping all the code in the .text section. As a nice side benefit, grouping code into the same section saves on the amount of ROM required for the code. Each section must start on a 4k boundary, so on average each section will waste 2k or ROM. Note that section names are case sensitive, so .TEXT is not the same as .text.&nbsp;</FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif>Here are some other related details about sections which I've shamelessly stolen from some other developers here at MS:</FONT></P>
<P><FONT face=arial,helvetica,sans-serif color=#0000cc><STRONG>Paging:</STRONG></FONT></P>
<P><FONT face=arial,helvetica,sans-serif>Code may be paged into a size-limited RAM buffer called a "page pool". The page pool helps limit the RAM impact of code by keeping resident only the code pages currently in use.&nbsp;Code that must always stay resident in RAM can be marked as non-pageable, but this will cause the full extent of that code section to be copied into RAM for as long as the module is loaded.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif>To limit the footprint of a module in the page pool, it’s best to group the functions and constant data that are in the working set together.<SPAN>&nbsp; </SPAN>This will allow the working set of code to exist in the page pool in the smallest number of pages. You can group them together using custom section naming. If section names are unique they will each be page-aligned (4k), so unless they truly need unique attributes, it’s best to name them such that automatic section merging can take place. Automatic section merging happens on sections named using a “section_name$subsection_name” convention, such that they all merge into one section named “section_name”.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif>For readability, give the subsection a name related to the grouping reason, such as “initialization”, “debug”, or “core”. </FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<H2 style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#4f81bd size=2>Example</FONT></H2>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif>To group function1 and function3 together in a custom subsection, you can do the following.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<DIV style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 0.5in; BORDER-LEFT: windowtext 1pt solid; MARGIN-RIGHT: 0in; PADDING-TOP: 1pt; BORDER-BOTTOM: windowtext 1pt solid; mso-element: para-border-div">
<P class=MsoNormal style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0in; BORDER-TOP: medium none; PADDING-LEFT: 0in; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 0in; MARGIN: 0in 0in 0pt; BORDER-LEFT: medium none; PADDING-TOP: 0in; BORDER-BOTTOM: medium none"><FONT face=arial,helvetica,sans-serif><FONT size=2><SPAN style="FONT-SIZE: 8pt; BACKGROUND: yellow; FONT-FAMILY: Consolas">#pragma code_seg(".text$initialization")</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: Consolas"><SPAN>&nbsp; </SPAN>// Code that follows goes into named subsection</SPAN></FONT></FONT></P>
<P class=MsoNormal style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0in; BORDER-TOP: medium none; PADDING-LEFT: 0in; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 0in; MARGIN: 0in 0in 0pt; BORDER-LEFT: medium none; PADDING-TOP: 0in; BORDER-BOTTOM: medium none"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: Consolas"><FONT face=arial,helvetica,sans-serif size=2>void function1(void)<SPAN>&nbsp; </SPAN>{return;}</FONT></SPAN></P>
<P class=MsoNormal style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0in; BORDER-TOP: medium none; PADDING-LEFT: 0in; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 0in; MARGIN: 0in 0in 0pt; BORDER-LEFT: medium none; PADDING-TOP: 0in; BORDER-BOTTOM: medium none"><FONT face=arial,helvetica,sans-serif><FONT size=2><SPAN style="FONT-SIZE: 8pt; BACKGROUND: lime; FONT-FAMILY: Consolas">#pragma code_seg()</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: Consolas"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>// Code that follows goes into default .text section</SPAN></FONT></FONT></P>
<P class=MsoNormal style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0in; BORDER-TOP: medium none; PADDING-LEFT: 0in; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 0in; MARGIN: 0in 0in 0pt; BORDER-LEFT: medium none; PADDING-TOP: 0in; BORDER-BOTTOM: medium none"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: Consolas"><FONT face=arial,helvetica,sans-serif size=2>void function2(void)<SPAN>&nbsp; </SPAN>{return;}</FONT></SPAN></P>
<P class=MsoNormal style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0in; BORDER-TOP: medium none; PADDING-LEFT: 0in; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 0in; MARGIN: 0in 0in 0pt; BORDER-LEFT: medium none; PADDING-TOP: 0in; BORDER-BOTTOM: medium none"><FONT face=arial,helvetica,sans-serif><FONT size=2><SPAN style="FONT-SIZE: 8pt; BACKGROUND: yellow; FONT-FAMILY: Consolas">#pragma code_seg(".text$initialization")</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: Consolas"><SPAN>&nbsp; </SPAN>// Code that follows goes into named subsection</SPAN></FONT></FONT></P>
<P class=MsoNormal style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0in; BORDER-TOP: medium none; PADDING-LEFT: 0in; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 0in; MARGIN: 0in 0in 0pt; BORDER-LEFT: medium none; PADDING-TOP: 0in; BORDER-BOTTOM: medium none"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: Consolas"><FONT face=arial,helvetica,sans-serif size=2>void function3(void)<SPAN>&nbsp; </SPAN>{return;}</FONT></SPAN></P>
<P class=MsoNormal style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0in; BORDER-TOP: medium none; PADDING-LEFT: 0in; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 0in; MARGIN: 0in 0in 0pt; BORDER-LEFT: medium none; PADDING-TOP: 0in; BORDER-BOTTOM: medium none"><FONT face=arial,helvetica,sans-serif><FONT size=2><SPAN style="FONT-SIZE: 8pt; BACKGROUND: lime; FONT-FAMILY: Consolas">#pragma code_seg()</SPAN><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: Consolas"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>// Code that follows goes into default .text section</SPAN></FONT></FONT></P></DIV>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<H2 style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#4f81bd size=2>Non-Pageable Sections</FONT></H2>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif>If you need only a small bit of the code to stay in RAM always for performance or reliability reasons (like time-critical driver code), you can make the module <I>partially</I> pageable by creating a completely new section with custom attributes.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif>The following pragma defines a section called "NonPageableCode" which is set to non-pageable.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<DIV style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 0.5in; BORDER-LEFT: windowtext 1pt solid; MARGIN-RIGHT: 0in; PADDING-TOP: 1pt; BORDER-BOTTOM: windowtext 1pt solid; mso-element: para-border-div">
<P class=MsoNormal style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0in; BORDER-TOP: medium none; PADDING-LEFT: 0in; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 0in; MARGIN: 0in 0in 0pt; BORDER-LEFT: medium none; PADDING-TOP: 0in; BORDER-BOTTOM: medium none"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: Consolas"><FONT face=arial,helvetica,sans-serif size=2>#pragma comment(linker, "/SECTION: NonPageableCode,ER!P")</FONT></SPAN></P></DIV>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif>There is also an newer, more readable&nbsp;way of specifying the section properties which has been available since CE5:</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<DIV style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 0.5in; BORDER-LEFT: windowtext 1pt solid; MARGIN-RIGHT: 0in; PADDING-TOP: 1pt; BORDER-BOTTOM: windowtext 1pt solid; mso-element: para-border-div"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: Consolas"><FONT face=arial,helvetica,sans-serif><FONT size=2><FONT color=#000000>#pragma </FONT><SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'; mso-fareast-font-family: Calibri; mso-bidi-font-family: 'Times New Roman'; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"><FONT color=#000000>section("NonPageableCode", execute, read, nopage)</FONT></SPAN></FONT></FONT></SPAN></DIV>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif>Now, in the source code, to make a section of code non-pageable, put the following line before the code:</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<DIV style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 0.5in; BORDER-LEFT: windowtext 1pt solid; MARGIN-RIGHT: 0in; PADDING-TOP: 1pt; BORDER-BOTTOM: windowtext 1pt solid; mso-element: para-border-div">
<P class=MsoNormal style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0in; BORDER-TOP: medium none; PADDING-LEFT: 0in; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 0in; MARGIN: 0in 0in 0pt; BORDER-LEFT: medium none; PADDING-TOP: 0in; BORDER-BOTTOM: medium none"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: Consolas"><FONT face=arial,helvetica,sans-serif size=2>#pragma code_seg("NonPageableCode")</FONT></SPAN></P></DIV>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif>Afterward, you may use the following line to force following code to be placed back in the default .text section:</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<DIV style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 0.5in; BORDER-LEFT: windowtext 1pt solid; MARGIN-RIGHT: 0in; PADDING-TOP: 1pt; BORDER-BOTTOM: windowtext 1pt solid; mso-element: para-border-div">
<P class=MsoNormal style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0in; BORDER-TOP: medium none; PADDING-LEFT: 0in; BACKGROUND: #f2f2f2; PADDING-BOTTOM: 0in; MARGIN: 0in 0in 0pt; BORDER-LEFT: medium none; PADDING-TOP: 0in; BORDER-BOTTOM: medium none"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: Consolas"><FONT face=arial,helvetica,sans-serif size=2>#pragma code_seg()</FONT></SPAN></P></DIV>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif></FONT>&nbsp;</P>
<H2 style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#4f81bd size=2>Tools</FONT></H2>
<P class=MsoListParagraph style="BACKGROUND: white; MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: -0.25in"><SPAN style="FONT-FAMILY: Consolas"><A href="http://support.microsoft.com/kb/177429" mce_href="http://support.microsoft.com/kb/177429"><FONT face=arial,helvetica,sans-serif>DUMPBIN</FONT></A><FONT face=arial,helvetica,sans-serif>&nbsp;/HEADERS FOO.DLL (to see what sections exist in the module)</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=2>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=2>That's it for now.</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"><o:p></o:p></SPAN><FONT face=arial,helvetica,sans-serif>&nbsp;</FONT></P>]]></content:encoded>
    </item>
    <item>
      <title>DLL Forwarders in Windows CE</title>
      <link>https://docs.microsoft.com/archive/blogs/medmedia/dll-forwarders-in-windows-ce</link>
      <pubDate>Tue, 29 Jan 2008 12:45:00 GMT</pubDate>
      <dc:creator><![CDATA[Andy Raffman]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/medmedia/2008/01/29/dll-forwarders-in-windows-ce/</guid>
      <description><![CDATA[I haven't seen this information&nbsp;consolidated online, so here it is:
&nbsp;
A DLL Forwarder is...]]></description>
      <content:encoded><![CDATA[<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva>I haven't seen this information&nbsp;consolidated online, so here it is:</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva>A DLL Forwarder is used&nbsp;if you want to export an entry point from one DLL (or,&nbsp;more likely, for historical purposes you've already exported it from&nbsp;one dll), but you want to actually implement it in a different DLL.</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva>For example, suppose you want to implement a function Foo() in a DLL I'll call impl.dll, but for whatever reason you need to export it from a DLL I'll call export.dll. Of&nbsp;course, one simple solution is to&nbsp;add code to export.dll to explicitly call into impl.dll. However, there are a couple of issues with this:</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva>-&nbsp;There's an additional&nbsp;function call/return&nbsp;overhead.</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva>- If the functions exported from the two DLLs have the same name, you might have some trouble convincing the linker to call the the Foo() in impl.dll from the Foo() in export.dll.</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva>A forwarder solves this problem by directly interacting with the loader to forward exports from one DLL to another DLL without actually adding anything to the code path.</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva>Forwarders are implemented in the .def file of the DLL you're forwarding through, and have the following syntax:</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true"><FONT face=verdana,geneva></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"><FONT face=verdana,geneva>EXPORTS</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"><FONT face=verdana,geneva>&nbsp;&nbsp;&nbsp; </FONT><A href="mailto:SHIM_ORD_1861=COREDLX.@1861" mce_href="mailto:SHIM_ORD_1861=COREDLX.@1861"><SPAN style="COLOR: windowtext; TEXT-DECORATION: none; text-underline: none"><FONT face=verdana,geneva>&lt;<STRONG>FuncName</STRONG>&gt;=&lt;<STRONG>ForwardedDll</STRONG>&gt;.&lt;<STRONG>ForwardedFuncName</STRONG>&gt;|#&lt;<STRONG>ForwardedOrdinal</STRONG>&gt;</FONT></SPAN></A><FONT face=verdana,geneva> @&lt;<STRONG>FuncOrdinal</STRONG>&gt; NONAME</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p><FONT face=verdana,geneva>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"><FONT face=verdana,geneva>Where:</FONT></SPAN><o:p><FONT face=verdana,geneva>&nbsp;</FONT></o:p></P>
<BLOCKQUOTE>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=verdana,geneva><B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">&lt;FuncName&gt;</SPAN></B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"> is the name of the function as exported (e.g. from export.dll).</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=verdana,geneva><B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">@&lt;FuncOrdinal&gt;</SPAN></B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"> is the ordinal of the function as exported (e.g. from export.dll). Note the use of the '@' symbol. Optional.</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva></FONT></SPAN></B>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=verdana,geneva><B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">&lt;ForwardedDll&gt;</SPAN></B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"> is the name of the DLL into which you're forwarding the call (e.g. into impl.dll).&nbsp;Optional; if not specified, the forwarded function is assumed to be in this dll.</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><FONT face=verdana,geneva></FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=verdana,geneva><B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">&lt;ForwardedFuncName&gt;</SPAN></B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"> is the name of the function in the ForwardedDll.</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=verdana,geneva><B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">#&lt;ForwardedOrdinal&gt;</SPAN></B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"> is the ordinal of the function in the ForwardedDll. Note the use of the '#' symbol.</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=verdana,geneva><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"></SPAN></FONT>&nbsp;</P><FONT face=verdana,geneva><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=verdana,geneva><B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">NONAME</SPAN></B><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">&nbsp;is the keyword that causes the linker to throw away the name of the function you're exporting so that it can only be referenced by its ordinal. This saves some space in the DLL and forces all callers to use the ordinal to link or GetProcAddress on the function. Optional.</SPAN></FONT></P><o:p></o:p></SPAN></FONT></BLOCKQUOTE>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><FONT face=verdana,geneva></FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva>Note: You need to specify the forwarded function name or ordinal (not both). You'll get slightly better load perf and smaller code size by specifying the ordinal. The ordinal is also necessary if the function in the DLL you're forwarding to is specified as NONAME in its def file.<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><FONT face=verdana,geneva>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva>Using our example, to forward Foo() from export.dll to impl.dll, the export.def file would have a line that looks like this:</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva>EXPORTS&nbsp;</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=verdana,geneva>&nbsp;&nbsp;&nbsp; Foo = impl.Foo</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=Verdana></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=Verdana>If you run "dumpbin /exports" against export.dll, you should see an entry for showing the forward that looks something like this:</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><FONT face=Verdana></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face="courier new,courier"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">&nbsp;&nbsp;&nbsp; ordinal&nbsp; hint &nbsp; RVA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name<BR></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">&nbsp;&nbsp;&nbsp; nnnn&nbsp;&nbsp;&nbsp; mm&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Foo (forwarded to Impl.Foo)</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face=verdana,geneva>&nbsp;</FONT></o:p></P><o:p>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d"><FONT color=#000000><FONT face=verdana,geneva>Tricky detail 1: When linking export.dll, the linker needs to figure out that the function you're exporting is a "C" style function, which it would normally do by looking at the function signature in the code implementation of the function. I've found that the easiest way to work around this is to implement a code stub that is linked into export.dll so it can get the right name in the export.lib file (e.g. decorated/undecorated).&nbsp;The actual code is thrown away at link time, so it doesn't contribute to the size of the Dll. For example, one would need to implement&nbsp;the following and link it into export.dll to make the linker happy. <o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d"><o:p><FONT face=verdana,geneva color=#000000>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><SPAN style="COLOR: #1f497d"><FONT color=#000000><FONT face=verdana,geneva>#define FORWARD(fn) extern "C" void fn(){}<o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><SPAN style="COLOR: #1f497d"><FONT face=verdana,geneva color=#000000>FORWARD(Foo)</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d"><o:p><FONT face=verdana,geneva color=#000000>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d"><o:p><FONT color=#000000><FONT color=#000000><FONT face=verdana,geneva>Tricky detail 2: I've run into&nbsp;one issue with ROMIMAGE:&nbsp;if&nbsp;export.dll is in the modules section of the .bib file, but impl.dll is in the files section, ROMIMAGE will generate an error when it tries to resolve the import at makeimg time. This will likely be fixed in the future, but for now it's just something that needs to be avoided.</FONT></FONT></FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d"><o:p><FONT color=#000000><FONT face=verdana,geneva></FONT></P></FONT></o:p></SPAN></o:p>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true">&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt">Tricky detail 3:&nbsp;Forwarders&nbsp;are used at load time to forward references between DLLs. The linker will not use forwarders at link time to resolve&nbsp;links within your DLL. Therefore, if the DLL you're forwarding from includes&nbsp;code with references to the function you're forwarding, the link phase of you DLL will fail with an unresolved extern error.</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true">&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt">Tricky example: <SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">If you want to&nbsp;export it a&nbsp;function at&nbsp;ordinal 1000 (and not export it by name), and want to forward it to&nbsp; DLL&nbsp;which&nbsp;exports it at ordinal&nbsp;2000 (without a name), the syntax in your .def file is:</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true">&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'">EXPORTS</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; <A href="mailto:SHIM_ORD_1000=IMPL.@2000"><SPAN style="COLOR: windowtext; TEXT-DECORATION: none; text-underline: none">SHIM_ORD_1000=IMPL.@2000</SPAN></A> @1000 NONAME</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true">&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">The SHIM_ORD_1000 is an <EM>arbitrary name</EM>; it's only there to satisfy the&nbsp;def file syntax rules. It&nbsp;doesn't really matter what you call it as long as it doesn't alias to anther function exported in your .def. If you then run dumpbin /exports on the resulting dll, you'll see something like:</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true">&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; 1000 [NONAME] (forwarded to <A href="mailto:IMPL.@2000"><SPAN style="COLOR: windowtext; TEXT-DECORATION: none; text-underline: none">IMPL.@2000</SPAN></A>)</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true">&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true">&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>More about A/V synchronization in DShow</title>
      <link>https://docs.microsoft.com/archive/blogs/medmedia/more-about-av-synchronization-in-dshow</link>
      <pubDate>Tue, 02 Oct 2007 17:47:00 GMT</pubDate>
      <dc:creator><![CDATA[luciad]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/medmedia/2007/10/02/more-about-av-synchronization-in-dshow/</guid>
      <description><![CDATA[In our previous entry, we talked about how video is synchronized to audio. In this short entry, we...]]></description>
      <content:encoded><![CDATA[<P>In our previous entry, we talked about how video is synchronized to audio. In this short entry, we will talk&nbsp;about&nbsp;time stamps, master clocks, how adjustments to the master clock are made and&nbsp;how to deal with live streams.</P>
<P><STRONG>About Reference Clocks and Stream Time</STRONG></P>
<P>All fiters in a filter graph are synchronized to the same clock, the reference clock. The stream time is based off the reference time, but it is relative, and depends on which state the graph is. For instance, stream time doesn't move when the graph is paused; stream time goes back to 0 after a seek.</P>
<P>DirectShow provides a base class CBaseReferenceClock that implements the IReferenceClock interface.&nbsp;The base class clock object maintains two <EM>times </EM>internally:</P>
<UL>
<LI>internal private time</LI>
<LI>reference time</LI></UL>
<P>The internal private time is the actual time kept by the clock, and can be accessed through GetPrivateTime(). The internal private time can go backwards for brief periods of time. The reference time is based off the private time, and cannot go backwards.</P>
<P>Whenever a filter provides the reference clock, it will usually inherit from CBaseReferenceClock. It can either override the GetPrivateTime() function to return directly the time from the device (if available), or it can issue adjustments to the stream time through the SetTimeDelta() function.&nbsp;If it chooses the second method, it will need to monitor the difference between the system time and the time provided by the device.</P>
<P>The default reference clock in WindowsCE is provided by our audio renderer. It uses the SetTimeDelta() method to issue adjustments to the stream time. To change the reference clock in a filter graph, the interface IMediaFilter needs to be queried from the filter graph. Then use SetSyncSource() to change the reference clock.</P>
<P>All filters can access both the reference time and the stream time. The base filter class CBaseFilter has a m_pClock member. The reference time can be accessed by doing m_pClock-&gt;GetTime(), and the stream time is a member function of CBaseFilter, StreamTime().</P>
<P><STRONG>About Time Stamps &amp; Stream Time</STRONG></P>
<P>The samples&nbsp;being processed in the filter graph may or may not have a time stamp, which is the media sample start and finish time. The time stamps are used in conjuction with the stream time. If a sample has a time stamp that is&nbsp;greater than the current stream time, it means that the sample is <EM>early</EM>. If a sample has a time stamp that is&nbsp;smaller than the current stream time, it is <EM>late</EM>. In a playback scenario, usually&nbsp;a splitter is the one that attaches time stamps to the samples. Filters may use time stamps for different reasons. For instance, time stamps may be used for presentation purposes, or to control the amount of buffering. The video renderer will use time stamps to schedule the samples for presentation, and thus, will end up throttling the video playback pipeline. When a sample arrives at the video renderer, there are several possibilities:</P>
<UL>
<LI>no timestamp - sample is scheduled immediately</LI>
<LI>in the future&nbsp;(timestamp&nbsp;&gt; stream time)&nbsp;- video renderer needs to schedule the sample, and will usually call m_pClock-&gt;AdviseTime()</LI>
<LI>in the past&nbsp;(timestamp&nbsp;&lt; stream time) - may render immediately, or not render at all.</LI></UL>
<P><STRONG>The&nbsp;Reference Clock &amp; The Audio Renderer</STRONG></P>
<P>Let's assume in this section that the default Windows CE audio renderer is the reference clock. The audio renderer uses time stamps and stream time in a different way. Being the&nbsp;reference clock implies that the stream time is controlled by this component, so it will not follow a behavior similar to the video renderer. </P>
<P>In this case, as soon as the audio renderer receives a sample, it is ready to send it out to the audio driver. If the sample is late, it will drop it. Otherwise,&nbsp;it will send&nbsp;them immediately if there's buffer availability from the audio driver. It will never wait for the time to be <EM>right</EM>. For cases where the media sample times are not contiguous, that is, the end time of a sample is smaller than the start time of the next sample, then the audio renderer will write silence to the driver, and will wait until the start time for the second sample has arrived. In the normal scenario, there is going to be no space between media samples, so the audio renderer will write samples as fast as it can.</P>
<P>When the default audio renderer has finished processing a sample, it will read the device clock and the system clock, and compute the difference between them. Unfortunately, there is no way to get to the device clock directly, so the audio renderer uses the <FONT size=2>amsndOutGetPosition(), which can be imprecise.&nbsp;The audio renderer will accumulate differences, and will use a low pass filter on these differences. Whenever the average difference has gone above a certain threshold, then it will issue an adjustment to the stream time, through the usage of the SetTimeDelta() function. As soon as it does that, all filters calling GetTime() will receive the adjusted time - so the stream time will not be continuous. Note that all other filters that used m_pClock-&gt;AdviseTime() to get notified when a certain stream time has arrived (such as the video renderer) will not have to know of the stream time "change" that happened because of an adjustment. They will be advised when the stream time reached the desired value.</FONT></P>
<P><FONT size=2><STRONG>Live Sources &amp; Clock Slaving</STRONG></FONT></P>
<P><FONT size=2>If the default Windows CE audio renderer is not the&nbsp;reference clock, it will write samples as it receives them. There's no automatic slave mode in WindowsCE, so the audio renderer will not wait for the time to be right before it sends the next sample.</FONT></P>
<P><FONT size=2>For the case of live streams, there is one interface in our audio renderer that causes a speed up or slow down in the audio driver so that we try to match against the live source. The source filter will usually be using the IAudioRenderer-&gt;SetDriftRate() to control the audio matching speed. In this case, the audio renderer continues to be the master clock.</FONT></P>
<P><FONT size=2>Another possibility when the audio renderer can't be the master clock is to simulate a <EM>slaving</EM> mode by&nbsp;inserting a filter in front of the audio renderer. This filter's responsibility would be to throttle the samples, so that they will be delivered just when it is <EM>almost</EM> time to send them to the audio driver. Of course, more complicated schemes are possible to try to match the rate of the incoming samples, but we will not go there here...</P></FONT>]]></content:encoded>
    </item>
    <item>
      <title>Wavedev2 Porting Guide</title>
      <link>https://docs.microsoft.com/archive/blogs/medmedia/wavedev2-porting-guide</link>
      <pubDate>Wed, 19 Sep 2007 21:36:00 GMT</pubDate>
      <dc:creator><![CDATA[Andy Raffman]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/medmedia/2007/09/19/wavedev2-porting-guide/</guid>
      <description><![CDATA[Foreword&nbsp;
I've been working on a wavedev2 porting guide over the last few weeks and decided...]]></description>
      <content:encoded><![CDATA[<P style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=5>Foreword&nbsp;</FONT></P>
<P style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>I've been working on a wavedev2 porting guide over the last few weeks and decided that it's better to post what I've go so far rather than wait&nbsp;until&nbsp;it's what I would consider finished.&nbsp;Expect future updates/additions as time allows, and feel free to ask&nbsp;for specific information in the comments.&nbsp;</FONT></P>
<P style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=5>Overview</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This whitepaper gives an overview of porting the wavedev2 audio driver to new hardware. For additional background on the history and features of wavedev2, please refer to other articles on </FONT><A href="http://blogs.msdn.com/medmedia" mce_href="http://blogs.msdn.com/medmedia"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>http://blogs.msdn.com/medmedia</FONT></A><FONT face=arial,helvetica,sans-serif color=#000000 size=3>.</FONT></P><FONT face=arial,helvetica,sans-serif color=#000000 size=3>
<P style="MARGIN: 10pt 0in 0pt"><FONT size=5>Different Versions</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt" mce_keep="true">&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt">Like most software, each release of Windows CE includes new features and bug fixes. For this article I’ll be referring to the version of wavedev2 which shipped with Windows CE 6 (AKA Yamazaki) under public\COMMON\oak\drivers\wavedev\wavedev2\ensoniq. This version is backward compatible with previous versions and the porting process is comparable. I’ve included some notes on the differences between Windows CE 6 and previous implementations at the end.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3><FONT size=5>File Layout</FONT>&nbsp;</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>All the files needed to build wavedev2 are in a single directory. For porting purposes, these files can be grouped into the following categories:</FONT></P>
<P class=MsoListParagraph style="MARGIN: 0in 0in 10pt 0.5in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l1 level1 lfo1"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>1.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Files which are device independent, and which you should not need to touch during the porting process beyond just copying them:</FONT></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>audiosys.h: Proprietary wave message definitions used by wavedev2.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>devctxt.cpp: Implementation of device context class.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>devctxt.h: Definition of device context class.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>input.cpp: Implementation of audio input streams.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>makefile: Used by build system</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>midinote.cpp: Implementation of tone generator.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>midistrm.cpp: Implementation of MIDI stream and MIDI parser.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>midistrm.h: Definition of MIDI note and stream classes.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>mixerdrv.cpp: Implementation of Mixer API classes (* may need to change if you want to take advantages of mixer API extensions).</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>mixerdrv.h: Definition of MIXER API classes.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>output.cpp: Implementation of audio output streams.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>strmctxt.cpp: Implementation of base audio stream class.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>strmctxt.h: Definition of base, input, output stream classes.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>wavemain.cpp: Device driver interface.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>wavemain.h: Common include header used by all source files.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>wavepdd.h: Basic PCM sample definitions.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>wfmtmidi.h: MIDI structure definitions.</FONT></P>
<P class=MsoListParagraphCxSpFirst style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l1 level1 lfo1; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>2.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Files which are device dependent but are logically part of the wavedev2 driver infrastructure. These files will need to be copied and modified during the port. These files are:</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpLast style="MARGIN: 0in 0in 0pt 0.5in; mso-add-space: auto"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>hwctxt.cpp: Implementation of hardware context class.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>hwctxt.h: Definition of hardware context class.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>oemsettings.h: HW-specific definitions used by hw-independent code.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>sources: Used by build system.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>wavedev2_ensoniq.def: Driver exports. Probably just need to rename.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>wavedev2_ensoniq.reg: Registry entries used to install driver.</FONT></P>
<P class=MsoListParagraphCxSpFirst style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l1 level1 lfo1; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>3.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Files which are device dependent and are not logically part of the driver infrastructure. You can ignore these files in your port (unless they happen to be appropriate to your hardware). For the Ensoniq sample driver, these are:</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpMiddle style="MARGIN: 0in 0in 0pt 0.5in"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoListParagraphCxSpLast style="MARGIN: 0in 0in 0pt 1in; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>AC97.H: AC97 codec-specific definitions.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>Es1371.cpp: Ensoniq 1371-specific functions.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>Es1371.h: Ensoniq 1371-specific header.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>Hw_ac97.cpp: AC97 codec-specific functions.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>In the above list, note that the vast majority of files shouldn’t need to be touched, and there is really only one source file and two headers you will need to modify to bring up a driver. </FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif size=5>Class Descriptions</FONT></P>
<H1 style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=4>Class Overview</FONT></H1>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>The wavedev2 driver largely consists of three main base classes:</FONT></P>
<H2 style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=4>HardwareContext</FONT></H2>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This class represents the actual audio hardware. This is the only class you will typically need to modify to port the driver. It is the only device dependent class, and takes care of hardware initialization, power management, DMA and Codec control, handling audio interrupts, and any other proprietary features the driver may implement. There is one instantiated HardwareContext object in the driver which is pointed to by the g_pHWContext global variable. I’ll go into detail about each HardwareContext’s methods later.</FONT></P>
<H2 style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=4>DeviceContext</FONT></H2>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This class represents a specific audio device. You should not have to modify anything in this class to port the driver. There is a DeviceContext virtual base class, from which are derived an InputDeviceContext and an OutputDeviceContext. A typical wavedev2 audio driver (such as the Ensoniq driver) implements a single input device represented by an InputDeviceContext; and a single output device represented by an OutputDeviceContext. In the Ensoniq sample, these objects are directly embedded within HardwareContext class as member variables. </FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>DeviceContext methods include:</FONT></P>
<H2 style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=4>StreamContext</FONT></H2>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This class represents a specific audio stream. You should not have to modify anything in this class to port the driver. There is a StreamContext virtual base class from which are derived a variety of stream classes for various flavors of PCM audio and MIDI data. Each stream is associated with a specific device context. This association is implemented as a linked list of stream contexts hanging off of each device context. In addition, each stream context includes a pointer back to its associated device context.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>The class hierarchy is roughly as follows:</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>StreamContext</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; CMidiStream&nbsp;</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WaveStreamContext</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputStreamContext</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OutputStreamContext</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; OutputStreamContextM8</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OutputStreamContextM16</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OutputStreamContextS8</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OutputStreamContextS16</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>The reason for the multitude of output contexts is that the mixing/sample-rate-conversion code on the output side is optimized for each type of PCM data (Stereo/Mono, 8/16-bit samples). This avoids some tests in the inner loop. The same optimization wasn’t done for the input side (input isn’t typically used as often as output, and the code is a little simpler).</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>StreamContextMethods include:</FONT></P>
<H1 style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=5>Porting HardwareContext</FONT></H1>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>In this section, I’ll go over each of the methods in HardwareContext and describe what they do.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::CreateHWContext</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.25in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This is a static method which is called during driver initialization (from the WAV_Init code in wavemain.cpp). This function should create and initialize the global g_pHWContext with a new HardwareContext object and call g_pHWContext-&gt;Init. You probably won’t need to change this function, as most changes will be in the Init method.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::Init</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This method is only called by CreateHWContext, and is where initialization of the Hardware is typically implemented.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Portions of this function may need to be modified for new hardware. Its role is to initialize any hardware, allocate DMA buffers, and startup the interrupt service thread. In addition, during initialization it needs to call into some of the device independent sections to initialize them; specificially:</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoListParagraphCxSpFirst style="MARGIN: 0in 0in 0pt 0.75in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l3 level1 lfo2; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri"><SPAN style="mso-list: Ignore"><FONT size=3>-</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Call SetBaseSampleRate on each device context to tell it what sample rate the hardware is running at. Note that these functions can be called at any time to tell the device context that the hardware sample rate has changed, but for devices with a fixed sample rate setting this up during initialization makes sense.</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpLast style="MARGIN: 0in 0in 10pt 0.75in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l3 level1 lfo2; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri"><SPAN style="mso-list: Ignore"><FONT size=3>-</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Call InitMixerControls to initialize the Mixer API support.</FONT></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::Deinit</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This method is called when the driver is unloaded and the system calls WAV_Deinit. In the current design, wave drivers are never unloaded so this method has limited usefulness.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::UpdateOutputGain</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::UpdateInputGain</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::SetOutputGain</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::SetOutputMute</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::GetOutputGain</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::GetOutputMute</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::GetInputMute</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::SetInputMute</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::GetInputGain</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::SetInputGain</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>These methods are associated with the master input and output gain controls provided by the default mixer API implementation and the device gain waveOutSetVolume API. In the Ensoniq implementation these defer processing to the DeviceContext SetGain methods, which automatically handle volume control in software. There is no need to modify the existing code unless you want to handle some aspects of volume control in hardware. However, keep in mind that individual stream gain controls are still handled in software, and there is no additional overhead in handling device gain as well. Therefore, there is no performance advantage in modifying this code to use hardware gain controls.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::StartOutputDMA</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This method starts the DMA controller for audio output. This includes:</FONT></P>
<P class=MsoListParagraphCxSpFirst style="MARGIN: 0in 0in 0pt 0.75in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l2 level1 lfo3; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>1.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Check to see if output dma is already running and ignore the call if it is.</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpMiddle style="MARGIN: 0in 0in 0pt 0.75in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l2 level1 lfo3; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>2.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Clear the variables that track how much “live” data is in each DMA buffer.</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpMiddle style="MARGIN: 0in 0in 0pt 0.75in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l2 level1 lfo3; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>3.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>“Prime” the output DMA buffer with data.</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpLast style="MARGIN: 0in 0in 10pt 0.75in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l2 level1 lfo3; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>4.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Start the DMA channel if (and only if) data was available to be transferred.</FONT></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>The only line you should need to change is the one that specifically turns on the DMA channel, which in the Ensoniq implementation is:</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in; TEXT-INDENT: 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>m_CES1371.StartDMAChannel( ES1371_DAC0 );</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::StopOutputDMA</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT size=3><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>This method stops the audio output DMA controller. The only line you should need to change is:</FONT></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in; TEXT-INDENT: 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>m_CES1371.StopDMAChannel( ES1371_DAC0 );</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::StartInputDMA</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::StopInputDMA</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>These methods are analogous to the methods described above for the output DMA. However, note that the code to start the input DMA doesn’t need to “prime” the buffer or keep track of how much application data is in the buffer, and is therefore somewhat simpler than the output case.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::GetDriverRegValue</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::SetDriverRegValue</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>These methods relate to reading driver-specific registry keys. You should not need to change them.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::InitInterruptThread</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This method initializes the audio driver’s IST thread and sets it to a realtime priority. If your driver has a single IST thread shared by both input and output you will not need to modify this code.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::PowerUp</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::PowerDown</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>These methods are called by the system’s power management subsystem. In the Ensoniq driver they are stubbed out. </FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::TransferInputBuffer</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::TransferOutputBuffer</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This method is called from the IST to transfer one data into our out of the DMA buffers. The code determines the starting address and size of the DMA buffer and passes the information to the device context, which performs the actual transfer. You will not need to modify this code unless you change the organization or data structures representing the DMA buffers.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::InterruptThread</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This method implements the Interrupt Service Thread which is shared by both input and output DMA. It’s operation is basically:</FONT></P>
<P class=MsoListParagraphCxSpFirst style="MARGIN: 0in 0in 0pt 1in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l3 level2 lfo2; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>1.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Wait for an input or output DMA done interrupt.</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpMiddle style="MARGIN: 0in 0in 0pt 1in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l3 level2 lfo2; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>2.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Determine whether an input or output (or both) DMA interrupt occurred.</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpMiddle style="MARGIN: 0in 0in 0pt 1in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l3 level2 lfo2; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>3.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>If an output DMA interrupt occurred:</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpMiddle style="MARGIN: 0in 0in 0pt 1.5in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l3 level3 lfo2; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore"><FONT size=3>§</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Transfer/mix application data into the DMA buffer that was just completed.</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpMiddle style="MARGIN: 0in 0in 0pt 1.5in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l3 level3 lfo2; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore"><FONT size=3>§</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp; </SPAN></SPAN></SPAN><FONT size=3>If there is no application data remaining in either DMA buffer, halt output DMA</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpMiddle style="MARGIN: 0in 0in 0pt 1in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l3 level2 lfo2; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>4.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>If an input DMA interrupt occurred:</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpMiddle style="MARGIN: 0in 0in 0pt 1.5in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l3 level3 lfo2; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore"><FONT size=3>§</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Transfer data out of the DMA buffer that was just completed into application buffers.</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpMiddle style="MARGIN: 0in 0in 0pt 1.5in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l3 level3 lfo2; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore"><FONT size=3>§</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp; </SPAN></SPAN></SPAN><FONT size=3>If we were unable to transfer any data (due to no application buffer being available), halt input DMA.</FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpLast style="MARGIN: 0in 0in 0pt 1in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l3 level2 lfo2; mso-add-space: auto"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>5.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Go back to step 1.</FONT></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::SetSpeakerEnable</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::RecalcSpeakerEnable</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::ForceSpeaker</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>These methods handle the WODM_FORCESPEAKER message which may be used to request that audio data be routed to an auxiliary speaker on the back of the phone (this speaker is typically larger and more powerful than the earpiece speaker, and is used for ringtones). If you hardware supports this functionality, you will need to add code to the SetSpeakerEnable to switch the speaker on or off.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::PmControlMessage</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This method receives messages from the Power Manager IOCTL calls:</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>IOCTL_POWER_CAPABILITIES</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>IOCTL_POWER_QUERY</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 1in"><FONT size=3><FONT face=arial,helvetica,sans-serif><FONT color=#000000>IOCTL_POWER_SET<SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></FONT></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 1in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>IOCTL_POWER_GET</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 1in"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT size=3><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>You probably will not need to modify this code.</FONT></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>HardwareContext::IsSupportedOutputFormat</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>This method is called during waveOutOpen to allow the OEM to support additional custom audio formats beyond the standard PCM functionality. Normally this method should just return FALSE. The Ensoniq driver supports directly playing WMAPro compressed audio content over its S/PDIF interface and therefore returns TRUE for this specific case.</FONT></P>
<H1 style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=5>DMA Buffer Organization and Data Transfer</FONT></H1>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>In the Ensoniq implementation, which is fairly typical, input and output are each allocated a DMA buffer using HalAllocateCommonBuffer. The size of each buffer is only 4k (the same as a memory page), so it’s unlikely that the allocation will fail (especially since it takes place during boot). Other implementations may choose to preallocate a fixed area of memory for the audio DMA buffers.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>During audio transfer, each DMA buffer is logically subdivided into equally-sized DMA pages 0 and 1, and the hardware is programmed to:</FONT></P>
<P class=MsoListParagraphCxSpFirst style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l0 level1 lfo4"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>a.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Transfer nonstop from the DMA buffer to the codec, and automatically reload the DMA address register with the start address of the buffer when it reaches the end. </FONT></FONT></FONT></P>
<P class=MsoListParagraphCxSpLast style="MARGIN: 0in 0in 10pt 0.5in; TEXT-INDENT: -0.25in; LINE-HEIGHT: 115%; mso-list: l0 level1 lfo4"><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-fareast-font-family: Calibri; mso-bidi-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3>b.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3>Generate an interrupt to the audio system whenever the DMA address moves either past the midpoint of the buffer (e.g. from page 0 to page 1), or reaches the end and restarts itself (e.g. from page 1 to page 0).</FONT></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>On each DMA interrupt, the HardwareContext code needs to determine which DMA page the DMA controller has just finished copying data into/out of and call the DeviceContext’s TransferBuffer method to copy application data into/out of that buffer.</FONT></P>
<H1 style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=5>Buffer Security/Copying</FONT></H1>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>(Still working on this section)&nbsp;</FONT></o:p></P>
<H1 style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=5>Support for S/PDIF</FONT></H1>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>(Still working on this section)&nbsp;</FONT></o:p></P>
<P style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=5>Differences between Windows CE 5 &amp; Windows CE 6</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>All current versions of Windows Mobile (including Windows Mobile 6) are based on Windows CE 5 or earlier OS releases. However, the most recent version of wavedev2 is shipped with Windows CE 6, and that’s the version I’m examining for this guide. Therefore, it’s important to touch on differences between how the two OS’es interact with wave drivers.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>For the most part, the audio driver architecture between CE5 and CE6 is the same. Audio drivers written for CE5 can generally run with little or no modification on CE6. </FONT></P>
<H2 style="MARGIN: 10pt 0in 0pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=4>Virtual Addressing Differences</FONT></H2>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>When porting the Ensoniq wavedev2 driver from CE5 to CE6, the only change specifically related to moving between operating systems was to surround the call to SetProcPermissions in hwctxt.cpp as follows:</FONT></P>
<P class=MsoNoSpacing style="MARGIN: 0in 0in 0pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>#if (_WINCEOSVER &lt; 600)</FONT></P>
<P class=MsoNoSpacing style="MARGIN: 0in 0in 0pt 0.5in"><FONT size=3><FONT face=arial,helvetica,sans-serif><FONT color=#000000><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>SetProcPermissions((DWORD)-1);</FONT></FONT></FONT></P>
<P class=MsoNoSpacing style="MARGIN: 0in 0in 0pt 0.5in"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>#endif</FONT></P>
<P class=MsoNoSpacing style="MARGIN: 0in 0in 0pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>On Windows CE6, the API’s SetProcPermissions and GetProcPermissions are no longer supported due to changes in the virtual memory architecture. They are still exported for backward-compatibility purposes, but they will have no affect (other than printing out a nasty warning message on the debugger). This change bears a little explanation:</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>On pre-Windows CE6 systems there is a limit of 32 processes, and all processes run in a shared virtual memory space. The system provides cross-process protection to ensure that processes don’t access each other’s memory, and this protection is enforced on a per-thread basis. Device drivers (such as the wave driver) run inside device.exe, which is one of these 32 processes. The Interrupt Service Thread (IST) in the driver is responsible for accessing audio data in various application buffers residing in multiple processes. The audio driver’s IST overrides this protection by calling SetProcPermissions(0xFFFFFFFF); each bit in the parameter represents one of 32 processes in the system, so 0xFFFFFFFF enables access to all of them.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT face=arial,helvetica,sans-serif color=#000000 size=3>Windows CE 6 adopts a more traditional memory architecture, with the kernel taking the upper 2GB of virtual space and each user process occupying the same lower 2GB region. Switching between user processes involves swapping a new process into the lower 2GB. While this greatly expands the amount of virtual memory available to each user process, it also means that the IST thread (now running in the kernel) may no longer freely access other arbitrary process’ address space.</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><FONT size=3><FONT face=arial,helvetica,sans-serif><FONT color=#000000>To solve this problem, the waveapi middleware (which sits above the audio driver on the stack) now takes care of mapping each application data buffer into a kernel (via CeAllocAsynchronousBuffer). The memory mapping/unmapping take place during waveOutPrepareHeader/waveOutUnprepareHeader, so the cost of memory management doesn’t impact performance.<SPAN style="FONT-FAMILY: 'Courier New'"><o:p></o:p></SPAN></FONT></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 10pt"><o:p><FONT face=arial,helvetica,sans-serif color=#000000 size=3></FONT></o:p>&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>The Video Renderer Connection Process</title>
      <link>https://docs.microsoft.com/archive/blogs/medmedia/the-video-renderer-connection-process</link>
      <pubDate>Mon, 11 Jun 2007 12:28:00 GMT</pubDate>
      <dc:creator><![CDATA[luciad]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/medmedia/2007/06/11/the-video-renderer-connection-process/</guid>
      <description><![CDATA[The video renderer is the last filter in the video pipe, and it is&nbsp;responsible for displaying...]]></description>
      <content:encoded><![CDATA[<P>The video renderer is the last filter in the video pipe, and it is&nbsp;responsible for displaying the output of upstream filters.&nbsp;The video renderer&nbsp;is just a controller for the underlying display driver, and does not do any processing on the image samples themselves. </P>
<P>The video renderer operates in&nbsp;two distinct modes:</P>
<UL>
<LI>GDI</LI>
<LI>DirectDraw</LI></UL>
<P>When the graph is first connected, the video renderer always tries to connect using GDI, and for that, it will need a connection with an RGB media type that matches the display format of the primary monitor. Just when it goes into <EM>Paused </EM>mode, the video renderer will try to allocate surfaces using DirectDraw. This dual mode of operation was envisioned so as to always have a fall back plan in case DirectDraw surfaces were not available in some circumstances. </P>
<P><STRONG><U>Choosing an Accelerated Media Type</U></STRONG></P>
<P>When the video renderer goes into Paused mode, it is time to allocate the DirectDraw surfaces. The video renderer will do so by enumerating all media types of the upstream filter, and then trying to allocate a surface matching that media type. For instance, let's assume the upstream filter is the <EM>WMV DMO</EM>. It currently supports the following output media types (the preferred media type is the first one):</P>
<UL>
<LI>YV12</LI>
<LI>NV12</LI>
<LI>YUY2</LI>
<LI>I420</LI>
<LI>IYUV</LI>
<LI>UYVY</LI>
<LI>YVYU</LI>
<LI>RGB565</LI>
<LI>RGB555</LI>
<LI>RGB32</LI>
<LI>RGB24</LI>
<LI>RGB8</LI></UL>
<P mce_keep="true">The video renderer will try to allocate flipping overlay surfaces first, then non-flipping surfaces:</P>
<UL>
<UL>
<LI>
<DIV mce_keep="true">For each media type of the upstream filter, in the order dictated by the upstream filter</DIV></LI>
<UL>
<LI>
<DIV mce_keep="true">try to allocate a flipping surface of that media type</DIV></LI>
<LI>
<DIV mce_keep="true">If it succeeds, call QueryAccept on the upstream filter's output pin</DIV></LI>
<LI>
<DIV mce_keep="true">If it succeeds, use it</DIV></LI></UL>
<LI>If the previous didn't succeed, try to allocate a primary flipping surface (if enabled)</LI>
<UL>
<LI>
<DIV mce_keep="true">If it succeeds, call QueryAccept on the upstream filter's output pin</DIV></LI>
<LI>
<DIV mce_keep="true">If it succeeds, use it</DIV></LI></UL>
<LI>If the previous didn't succeed, for each media type of the upstream filter, in the order dictated by the upstream filter</LI>
<UL>
<LI>try to allocate a surface (not flipping) of that media type</LI>
<LI>
<DIV mce_keep="true">If it succeeds, call QueryAccept on the upstream filter's output pin</DIV></LI>
<LI>
<DIV mce_keep="true">If it succeeds, use it</DIV></LI></UL></UL></UL>
<P>In&nbsp;this way, if the upstream filter has optimized for certain YUV formats, it can control the choice of media type. In case the display driver can also provide a surface of that type, the accelerated media type is chosen. The whole process is driven by the upstream filter, with the display driver in a passive role.</P>
<P><STRONG><U>Dynamic Format Changes from the Video Renderer</U></STRONG></P>
<P mce_keep="true">Of course, for an optimal pipe, we would like to always have overlay flipping surfaces available. Nevertheless, that may not be the case in some situations. For instance, depending on the display driver capabilities, the flipping overlay may just be available when the user is watching the video at its original size. When the user is stretching or shrinking, overlays might not be available. This is controlled by the DirectDraw hardware capabilities dwMinOverlayStretch and dwMaxOverlayStretch (see <A href="http://msdn2.microsoft.com/en-us/library/aa915204.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa915204.aspx">http://msdn2.microsoft.com/en-us/library/aa915204.aspx</A>). So, if the display driver doesn't support overlay stretching, and the video renderer is currently using overlays, it will need to swap to GDI (and thus to RGB format), so that GDI will do the necessary scaling.</P>
<P mce_keep="true">Note that every time the upstream filter&nbsp;requests a new buffer from the video renderer,&nbsp;the video renderer will try to return a DirectDraw buffer.&nbsp;If all the conditions to use the DirectDraw buffer are OK (clipping, stretching, video memory, etc.), then it will use it.&nbsp;Just in case one of the conditions fail it will resort to using GDI.</P>
<P mce_keep="true"><STRONG><U>Debugging&nbsp;Video Renderer Connection Problems</U></STRONG></P>
<P mce_keep="true">We have seen some common connection problems when initially bringing up new decoder filters and/or capture drivers:</P>
<UL>
<LI>
<DIV mce_keep="true">Color space converter is inserted in the graph</DIV></LI>
<LI>
<DIV mce_keep="true">Video renderer doesn't connect</DIV></LI>
<LI>YUV surfaces are not being used, just GDI</LI></UL>
<P><U>Analyzing the DirectShow logs</U>&nbsp;</P>
<P>The&nbsp;first step in this case is to turn on the debug zones for the DirectShow DLL, quartz.dll, and observe the connection and video renderer messages.&nbsp;</P>
<UL>
<LI>Set it on the <STRONG>client</STRONG>&nbsp;when quartz.dll is already loaded (my preferred method ;-):</LI>
<UL>
<LI>Go to Target/CE debug zones, choose quartz.dll, and check the first four zones</LI></UL>
<LI>Set it on the <STRONG>host-side registry</STRONG>&nbsp;if you want to start with the zones turned on:</LI>
<UL>
<LI>Go to [HKEY_CURRENT_USER\Pegasus\Zones]</LI>
<LI>Add a DWORD value with the name quartz and set it to 0xf.</LI>
<LI>(see more information on debug zones at: <A href="http://blogs.msdn.com/ce_base/archive/2006/12/18/debug-messages-and-debug-zones-in-windows-ce.aspx">http://blogs.msdn.com/ce_base/archive/2006/12/18/debug-messages-and-debug-zones-in-windows-ce.aspx</A>)</LI></UL></UL>
<P>Run your test scenario, and save the debug output. Look for the section that says "Filter Graph Dump", and verify which filters got inserted in the graph. Here's an example of a filter graph dump:</P>
<BLOCKQUOTE>
<P mce_keep="true">Filter graph dump<BR>Filter 1a199a30 'Video Renderer' Iunknown 1a199a20<BR>&nbsp;&nbsp;&nbsp; Pin 1a199f10 Input (Input) connected to 1a0e1880<BR>Filter 1a0e1200 'WMVideo &amp; MPEG4 Decoder DMO' Iunknown 1a0e11f0<BR>&nbsp;&nbsp;&nbsp; Pin 1a0e16e0 in0 (Input) connected to 1a0e0600<BR>&nbsp;&nbsp;&nbsp; Pin 1a0e1880 out0 (PINDIR_OUTPUT) connected to 1a199f10<BR>&nbsp;&nbsp;&nbsp; Pin 1a0e1a00 ~out1 (PINDIR_OUTPUT) connected to 0<BR>Filter 1a0ecc60 'ASF ICM Handler' Iunknown 1a0ecc50<BR>&nbsp;&nbsp;&nbsp; Pin 1a0ecd70 In (Input) connected to 1a0aa3a0<BR>&nbsp;&nbsp;&nbsp; Pin 1a0e0600 Out (PINDIR_OUTPUT) connected to 1a0e16e0<BR>Filter 1a0ec240 'Audio Renderer' Iunknown 1a0ec230<BR>wo: GetPin, 0<BR>&nbsp;&nbsp;&nbsp; Pin 1a0ec4e0 Audio Input pin (rendered) (Input) connected to 1a0eb880<BR>Filter 1a0eb220 'WMAudio Decoder DMO' Iunknown 1a0eb210<BR>&nbsp;&nbsp;&nbsp; Pin 1a0eb660 in0 (Input) connected to 1a0ea800<BR>&nbsp;&nbsp;&nbsp; Pin 1a0eb880 out0 (PINDIR_OUTPUT) connected to 1a0ec4e0<BR>Filter 1a0e9380 'ASF ACM Handler' Iunknown 1a0e9370<BR>&nbsp;&nbsp;&nbsp; Pin 1a0e9490 In (Input) connected to 1a0aa000<BR>&nbsp;&nbsp;&nbsp; Pin 1a0ea800 Out (PINDIR_OUTPUT) connected to 1a0eb660<BR>Filter 1a0a2ae0 '\Hard Disk2\clips\wmv\0-1.asf' Iunknown 1a0a2ad0<BR>&nbsp;&nbsp;&nbsp; Pin 1a0aa000 Stream 1 (PINDIR_OUTPUT) connected to 1a0e9490<BR>&nbsp;&nbsp;&nbsp; Pin 1a0aa3a0 Stream 2 (PINDIR_OUTPUT) connected to 1a0ecd70<BR>End of filter graph dump<BR></P></BLOCKQUOTE>
<P>After that, verify which media type the video renderer is using when trying accelerated mode (and if it succeeded). Search for "Allocating video resources":</P>
<BLOCKQUOTE>
<P>Allocating video resources<BR>Initialising DCI/DirectDraw<BR>Searching for direct format<BR>Entering ReleaseSurfaces<BR>Entering HideOverlaySurface<BR>Enumerated 32315659<BR>Entering FindSurface<BR>Entering GetMediaType<BR>Not a RGB format<BR>Entering CreateYUVFlipping<BR>Entering CheckCreateOverlay<BR>GWES Hook fails surface creation. IDirectDraw::CreateSurface fails.<BR>No surface<BR>Entering ReleaseSurfaces<BR>Entering HideOverlaySurface<BR>Enumerated 3231564e<BR>Entering FindSurface<BR>Entering GetMediaType<BR>Not a RGB format<BR>Entering CreateYUVFlipping<BR>Entering CheckCreateOverlay<BR>GWES Hook fails surface creation. IDirectDraw::CreateSurface fails.<BR>No surface<BR>Entering ReleaseSurfaces<BR>Entering HideOverlaySurface<BR>Enumerated 32595559<BR>Entering FindSurface<BR>Entering GetMediaType<BR>Not a RGB format<BR>Entering CreateYUVFlipping<BR>Entering CheckCreateOverlay<BR>Entering InitOverlaySurface<BR>Entering InitDrawFormat<BR>Entering InitDrawFormat<BR>Entering GetDefaultColorKey<BR>Returning default colour key<BR>Entering InitDefaultColourKey<BR>Entering SetSurfaceSize<BR>Preparing source and destination rectangles<BR>Entering ClipPrepare<BR>Entering InitialiseClipper<BR>Entering InitialiseColourKey<BR>overlay color key on<BR>Colour key<BR>No palette<BR><STRONG>Found AMDDS_YUVFLP surface</STRONG><BR>Proposing output type&nbsp; M type MEDIATYPE_Video&nbsp; S type <STRONG>MEDIASUBTYPE_YUY2</STRONG><BR></P></BLOCKQUOTE>
<P>Note in the above log that the video renderer tried to create surfaces in the order&nbsp;specified by the WMV DMO. For the display driver in use for the above log, it managed to create a YUY2 surface, the third option for the WMV decoder. The last section in this blog entry has more information about FourCC codes.</P>
<P>Here are some solutions for common connection problems we have faced in the past.</P>
<P><U>Color Space Converter is inserted in the graph</U>&nbsp;</P>
<P>The number one problem is that the upstream filter doesn't&nbsp;report any RGB format, just YUV formats. If that's the case, the video renderer can't connect directly to the filter since it requires a matching RGB format. Usually, the color space converter will be inserted in the graph in these cases. We don't want this to happen, as it will imply a memory copy of each frame buffer, so we want to make sure the upstream filter does provide RGB formats.</P>
<P>Sometimes the color converted gets inserted in the graph even though the upstream filter does support the needed RGB format. This can happen because the upstream filter is requiring an alignment different than 1 when the allocator is being decided. Currently, the video renderer will just accept 1-byte alignments.</P>
<P>Another common reason for the color converter to be inserted in the graph is when the BITMAPINFOHEADER supplied by the upstream filter doesn't contain the bitmasks correctly at the end of BITMAPINFOHEADER that is passed when getting the output media types. Please make sure that the bitmasks are inserted correctly. For instance, for RGB565, we should have:</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pdwBitfield++&nbsp; = 0xF800;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: green">// Red – 5<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.5in; TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;*pdwBitfield++&nbsp; = 0x07E0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: green">// Green - 6<o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.5in; TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;*pdwBitfield&nbsp;&nbsp;&nbsp; = 0x001F;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: green">// Blue - 5<o:p></o:p></SPAN></SPAN></P>
<P><U>Graph doesn't connect at all</U></P>
<P>If the upstream filter just supports a subset of YUV formats, and none of these are recognized by the color space converter, then it won't be possible at all to connect the video renderer. Again, in this case the solution is for the upstream filter to provide RGB formats.</P>
<P><U>YUV Surfaces are not used, just GDI</U></P>
<P>Another common occurrence is for the upstream filters to provide allocators. If this is the case, the video renderer will be tied to not using DirectDraw (as it can't pass upstream memory buffers to DirectDraw). If we want the optimal overlay flipping path, the video renderer *needs* to be the allocator, so that it is possible for it to provide DirectDraw surfaces upstream.</P>
<P mce_keep="true"><STRONG>Surface Types: Controlling Which Surfaces the Video Renderer Creates</STRONG></P>
<P mce_keep="true">There are ways to control which accelerated surfaces the video renderer is allowed or not to create that are useful when debugging the connection process, specially to reduce the number of options and the number of tries in the display driver. This is controlled via a registry key (see <A href="http://msdn2.microsoft.com/en-us/library/aa930626.aspx">http://msdn2.microsoft.com/en-us/library/aa930626.aspx</A>):</P>
<P mce_keep="true"><STRONG>HKEY_LOCAL_MACHINE\Software\Microsoft\DirectX\DirectShow\Video Renderer\SurfaceTypes</STRONG></P>
<P>The following table shows the AMDDS values for use with the <B>SurfaceTypes</B> named value.</P>
<H3 class=subHeading><!----></H3>
<TABLE class="" style="BACKGROUND-COLOR: #cccccc" width="100%" border=1>
<TBODY>
<TR>
<TH class="">Flag </TH>
<TH class="">Hexadecimal value </TH>
<TH class="">Description </TH></TR>
<TR>
<TD class="">
<P>AMDDS_NONE</P></TD>
<TD class="">
<P>0x00</P></TD>
<TD class="">
<P>No support for Device Control Interface (DCI) or DirectDraw.</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_DCIPS</P></TD>
<TD class="">
<P>0x01</P></TD>
<TD class="">
<P>Use DCI primary surface.</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_PS</P></TD>
<TD class="">
<P>0x02</P></TD>
<TD class="">
<P>Use DirectDraw primary surface.</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_RGBOVR</P></TD>
<TD class="">
<P>0x04</P></TD>
<TD class="">
<P>RGB overlay surfaces.</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_YUVOVR</P></TD>
<TD class="">
<P>0x08</P></TD>
<TD class="">
<P>YUV overlay surfaces.</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_RGBOFF</P></TD>
<TD class="">
<P>0x10</P></TD>
<TD class="">
<P>RGB off-screen surfaces.</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_YUVOFF </P></TD>
<TD class="">
<P>0x20</P></TD>
<TD class="">
<P>YUV off-screen surfaces.</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_RGBFLP</P></TD>
<TD class="">
<P>0x40</P></TD>
<TD class="">
<P>RGB flipping surfaces.</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_YUVFLP</P></TD>
<TD class="">
<P>0x80</P></TD>
<TD class="">
<P>YUV flipping surfaces.</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_ALL</P></TD>
<TD class="">
<P>0xFF</P></TD>
<TD class="">
<P>Use all available surfaces.</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_DEFAULT</P></TD>
<TD class="">
<P>0xFF</P></TD>
<TD class="">
<P>Use all available surfaces.</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_YUV </P></TD>
<TD class="">
<P>0xA8</P></TD>
<TD class="">
<P>(AMDDS_YUVOFF | AMDDS_YUVOVR | AMDDS_YUVFLP)</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_RGB</P></TD>
<TD class="">
<P>0x58</P></TD>
<TD class="">
<P>(AMDDS_RGBOFF | AMDDS_RGBOVR | AMDDS_RGBFLP)</P></TD></TR>
<TR>
<TD class="">
<P>AMDDS_PRIMARY</P></TD>
<TD class="">
<P>0x03</P></TD>
<TD class="">
<P>(AMDDS_DCIPS | AMDDS_PS)</P></TD></TR></TBODY></TABLE>
<P mce_keep="true">If you just want to enable YUV overlay flipping surfaces for debugging purposes, you should set the SurfaceTypes registry key to AMDDS_YUVFLP. Remember to turn on all surfaces back on after you finished debugging your problem...</P>
<P><STRONG>About FourCC codes:</STRONG></P>
<P>Note that in the example log we list the FOURCC codes that are being used in the line <EM>"Enumerated 32315659"</EM>. Here's how to map this hex number into a character sequence that&nbsp;will help identify&nbsp;the code:</P>
<P>&nbsp;Enumerated 32315659 </P>
<P>0x32 = '2', 0x31 = '1', 0x56 = 'V', 0x59 = 'Y' ===&gt; <STRONG>0x32315659 = YV12</STRONG></P>
<P>&nbsp;Enumerated 3231564e</P>
<P>0x32 = '2', 0x31 = '1', 0x56 = 'V', 0x4e = 'N'&nbsp;===&gt; <STRONG>0x3231564e = NV12</STRONG></P>
<P>&nbsp;Enumerated 32595559</P>
<P>0x32 = '2', 0x59 = 'Y', 0x55 = 'U', 0x59 = 'Y' ===&gt; <STRONG>0x32595559 = YUY2</STRONG><BR></P>
<P>&nbsp;Enumerated 56555949</P>
<P>0x56 = 'V', 0x55 = 'U', 0x59 = 'Y', 0x49 = 'I' ===&gt; <STRONG>0x56555949 = IYUV</STRONG></P>
<P>&nbsp;Enumerated 59565955</P>
<P>0x59 = 'Y', 0x56 = 'V', 0x59 = 'Y', 0x55 = 'U' ===&gt; <STRONG>0x59565955 = UYVY</STRONG></P>
<P>&nbsp;Enumerated 55595659</P>
<P>0x55 = 'U', 0x59 = 'Y', 0x56 = 'V', 0x59 = 'Y' ===&gt; <STRONG>0x55595659 = YVYU</STRONG></P>
<P>Also, the file in public\directx\sdk\inc\uuids.h contains&nbsp;several FOURCC media subtypes definitions:</P>
<UL>
<LI><FONT color=#008000 size=1>// 32595559-0000-0010-8000-00AA00389B71 'YUY2' == MEDIASUBTYPE_YUY2</LI></FONT><FONT size=1>
<LI>OUR_GUID_ENTRY(MEDIASUBTYPE_YUY2,</LI>
<LI>0x32595559, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)</LI></FONT><FONT color=#008000 size=1>
<LI>// 55595659-0000-0010-8000-00AA00389B71 'YVYU' == MEDIASUBTYPE_YVYU</LI></FONT><FONT size=1>
<LI>OUR_GUID_ENTRY(MEDIASUBTYPE_YVYU,</LI>
<LI>0x55595659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)</LI></FONT><FONT color=#008000 size=1>
<LI>// 59565955-0000-0010-8000-00AA00389B71 'UYVY' == MEDIASUBTYPE_UYVY</LI></FONT><FONT size=1>
<LI>OUR_GUID_ENTRY(MEDIASUBTYPE_UYVY,</LI>
<LI>0x59565955, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)</LI></FONT><FONT color=#008000 size=1>
<LI>// 31313259-0000-0010-8000-00AA00389B71 'Y211' == MEDIASUBTYPE_Y211</LI></FONT><FONT size=1>
<LI>OUR_GUID_ENTRY(MEDIASUBTYPE_Y211,</LI>
<LI>0x31313259, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)</LI></FONT><FONT color=#008000 size=1>
<LI>// 32315659-0000-0010-8000-00AA00389B71 'YV12' == MEDIASUBTYPE_YV12</LI></FONT><FONT size=1>
<LI>OUR_GUID_ENTRY(MEDIASUBTYPE_YV12,</LI>
<LI>0x32315659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)</LI></FONT><FONT color=#008000 size=1>
<LI>// 36313259-0000-0010-8000-00AA00389B71 'YV16' == MEDIASUBTYPE_YV16</LI></FONT><FONT size=1>
<LI>OUR_GUID_ENTRY(MEDIASUBTYPE_YV16,</LI>
<LI>0x36315659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)</LI></FONT><FONT color=#008000 size=1>
<LI>// 56595549-0000-0010-8000-00AA00389B71 'IUYV' == MEDIASUBTYPE_IUYV</LI></FONT><FONT size=1>
<LI>OUR_GUID_ENTRY(MEDIASUBTYPE_IUYV,</LI>
<LI>0x56595549, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)</LI></FONT><FONT color=#008000 size=1>
<LI>// 3231564E-0000-0010-8000-00AA00389B71 'NV12' == MEDIASUBTYPE_NV12</LI></FONT><FONT size=1>
<LI>OUR_GUID_ENTRY(MEDIASUBTYPE_NV12,</LI>
<LI>0x3231564E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)</LI></FONT><FONT color=#008000 size=1>
<LI>// 30323449-0000-0010-8000-00AA00389B71 'I420' == MEDIASUBTYPE_I420</LI></FONT><FONT size=1>
<LI>OUR_GUID_ENTRY(MEDIASUBTYPE_I420,</LI>
<LI>0x30323449, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)</LI></FONT><FONT color=#008000 size=1>
<LI>// 56555949-0000-0010-8000-00AA00389B71 'IYUV' == MEDIASUBTYPE_IYUV</LI></FONT><FONT size=1>
<LI>OUR_GUID_ENTRY(MEDIASUBTYPE_IYUV,</LI>
<LI>0x56555949, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)</LI></UL>
<P mce_keep="true"></FONT>Please do leave feedback, and let us know if this has been useful. Thanks,</P>
<P mce_keep="true">Lucia</P>]]></content:encoded>
    </item>
    <item>
      <title>Basics of A/V synchronization in DirectShow</title>
      <link>https://docs.microsoft.com/archive/blogs/medmedia/basics-of-av-synchronization-in-directshow</link>
      <pubDate>Mon, 05 Mar 2007 18:28:00 GMT</pubDate>
      <dc:creator><![CDATA[luciad]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/medmedia/2007/03/05/basics-of-av-synchronization-in-directshow/</guid>
      <description><![CDATA[All filters in a DirectShow graph should be synchronized to the same clock, the reference clock. The...]]></description>
      <content:encoded><![CDATA[<P>All filters in a DirectShow graph should be synchronized to the same clock, the <EM>reference clock</EM>. The filter graph manager makes sure that it finds one component that will be the reference clock, in the following simplified order: user-specified clock, renderer (usually audio renderer), or system clock if none available before.</P>
<P>The <EM>stream time</EM> is based off the reference clock, but relative to the time the graph last started running (so the stream time doesn't move if the graph is paused). If a media sample that enters a renderer has a time stamp <EM>t, </EM>then it means it should be rendered at stream time <EM>t. </EM>This is the basic mechanism by which a/v synchronization occurs. </P>
<P>There is usually a crystal in the audio hardware though, and no guarantees that the hardware timer will match the system clock. That's why usually we have the audio renderer being the reference clock for the whole DirectShow graph. If the audio renderer receives a sample late, or if the audio clock is consistently drifting from the system clock, then the audio renderer will issue stream time adjustments. </P>
<P>An audio renderer implementation will usually inherit from the CBaseReferenceClock class, and will call SetTimeDelta() function whenever it needs to&nbsp;do an adjustment to the stream time. Note that it should use a low pass filter before sending adjustments to the master clock so that no unnecessary jittering is introduced.</P>
<P>As the video renderer uses the incoming timestamps to schedule samples for presentation, the scheduler is based off stream time, and the audio renderer has control to change the stream time, the video and audio renderer will be using the same timeline.</P>
<P><STRONG>About the Video Renderer &amp; Frame Dropping</STRONG></P>
<P>If the video is running slow, and all video frames are being rendered, then theoretically the video renderer will receive samples with timestamps in the past and schedule them for immediate rendering. If this situation continues to happen, what will happen is that the video is going to be behind audio. This shows the need for frame dropping.</P>
<P>In fact, audio and video synchronization in DirectShow works by a combination of two elements:</P>
<UL>
<LI>Audio renderer controlling the DirectShow stream time;</LI>
<LI>IQualityControl and IDMOQualityControl interfaces guiding frame dropping algorithm</LI></UL>
<P>Dropping frames at the video renderer level is of course not very effective. If using overlay flipping surfaces, for instance, dropping a frame doesn't get you much farther trying to catch up (because the flipping itself is very cheap). Even in the case of Blits, it is still going to help very little (rendering time is small compared to decoding time). That's why there is the need&nbsp;to indicate the state and lateness of the renderer to upstream filters/DMOs, which is done through the quality notification messages.</P>
<P>The video renderer originates the notification messages (since it is <STRONG>the</STRONG>&nbsp;filter that needs to run in real time), and sends&nbsp;them upstream.&nbsp;If the upstream filter is a decoder, and it can handle it, it doesn't pass the message upstream. If it can't handle, then&nbsp;it passes it upstream. Note that the video renderer will drop frames anyway if it is very late.</P>
<P>Here's a coarse&nbsp;example of how to use the Quality interface to be able to drop frames in a decoder filter:</P>
<BLOCKQUOTE>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">HRESULT CDecoderFilterPin::Notify(IBaseFilter *pSender, Quality q)<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (quality sink has been set)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // m_pQSink<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status = Pass Notify on the quality sink&nbsp;&nbsp; (base sender is the decoder filter now)<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.5in"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.5in"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">else<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.5in"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: 0.5in"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">if (has frame dropping algorithm)<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status = Call decoder filter to do frame dropping <o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (upstreamQualityControl)<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status = Pass Notify() on to upstream quality control interface (base sender is the decoder filter now)<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status = not handled;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: 0.5in"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.5in"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">}</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.5in"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">return status</SPAN></P><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p>}</o:p></SPAN></P></BLOCKQUOTE>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p>&nbsp;</o:p></SPAN></P><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p>
<P class=MsoPlainText style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-FAMILY: 'Arial','sans-serif'"><FONT size=2>The decoder needs to decide, given what the current time is (given by the IQualityControl/IDMOQualityControl interface) if it needs or not to drop frames. Algorithms for frame dropping can vary from the extremely simple to very complicate. An example of an extremely&nbsp;simple one follows:<o:p></o:p></FONT></SPAN></P>
<P class=MsoPlainText style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-FAMILY: 'Arial','sans-serif'"><o:p><FONT size=2>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoPlainText style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-FAMILY: 'Arial','sans-serif'"><FONT size=2>The quality notification message will indicate how late we were when we last rendered a video frame. A very simple algorithm would be to drop all frames until you arrive at that "time", so that catch-up happens fast:<o:p></o:p></FONT></SPAN></P></o:p></SPAN>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p>&nbsp;</o:p></SPAN></P>
<BLOCKQUOTE>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p>CatchupPTS = q.Late + q.Timestamp</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p>Drop all frames until PTS_frame &gt;= Catchup_PTS</o:p></SPAN></P></BLOCKQUOTE>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoPlainText style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-FAMILY: 'Arial','sans-serif'"><FONT size=2>Of course, there are many variations for this. If B-frames are available, start trying to catch up by dropping B-frames. If the decoder has decoding decoupled from output generation (or color conversion etc.), a first step when you're late is to start dropping the output generation, and try to catch up. If neither is working, then you may have to drop P-frames, in which case you'll have to wait until the next I-frame, which is never a good user experience because the spacing between I-frames may be large.<o:p></o:p></FONT></SPAN></P>
<P class=MsoPlainText style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-FAMILY: 'Arial','sans-serif'"><o:p><FONT size=2>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoPlainText style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-FAMILY: 'Arial','sans-serif'"><FONT size=2>When doing trick modes, the algorithm for dropping frames will usually be more forgiving, since frames are arriving at rates other than 1.0. In fact,&nbsp;at high-rates, all samples that the decoder receives are probably going to be key frames anyway. In this case,&nbsp;you may drop any frame without a significant penalty, making catch up much easier.</FONT></SPAN></P>
<P class=MsoPlainText style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-FAMILY: 'Arial','sans-serif'"><FONT size=2></FONT></SPAN>&nbsp;</P></SPAN>]]></content:encoded>
    </item>
    <item>
      <title>The Wavedev2 ForceSpeaker API</title>
      <link>https://docs.microsoft.com/archive/blogs/medmedia/the-wavedev2-forcespeaker-api</link>
      <pubDate>Tue, 16 Jan 2007 19:54:00 GMT</pubDate>
      <dc:creator><![CDATA[Andy Raffman]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/medmedia/2007/01/16/the-wavedev2-forcespeaker-api/</guid>
      <description><![CDATA[This is just a&nbsp;quick note describing the behavior of the MM_WOM_FORCESPEAKER API built into the...]]></description>
      <content:encoded><![CDATA[<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">This is just a&nbsp;quick note describing the behavior of the MM_WOM_FORCESPEAKER API built into the wavedev2 wave driver.</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">One issue in Smartphone devices is determining where to route ringtones and other high-priority notifications. This is driven by two scenarios:</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">1. A fairly common design feature of&nbsp;Smartphone devices is a separate&nbsp;"high-volume" speaker on the rear of the device to play ringtones or fairly loud notifications. The OEM may want most system sounds to play through the normal handset speaker, but to have incoming call ringtones routed through the rear speaker.</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">2. When the user has a headset plugged in, all audio is routed to that headset. However, what about the situation where the headset is plugged in but the user isn't wearing it? For this reason, some OEMs <U>may</U> choose to play ringtones through the device speaker even if a headset is attached.</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">The common thread to each of these scenarios is that the audio device driver needs to make some decision about where to route the audio based on w</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">hether the sound being played is a ringtone (or other high-priority notification), or is just normal audio such as music being played through media player. </SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">The wave API doesn't include any built-in provision for the wave driver to determine who is trying to play a sound or where it should be routed. One might use the mixer API to address this, but the&nbsp;mixer&nbsp;API is somewhat complicated and doesn't lend itself to handling this on a per-wave-stream basis. Instead, when we first developed the wavedev2 driver back in 2000,&nbsp;we defined a proprietary wave message, MM_WOM_FORCESPEAKER, which&nbsp;is sent to the driver as a hint that the associated wave stream is a ringtone or notification that&nbsp;should possibly&nbsp;be played over over the device's speaker.</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">The format of this call is:&nbsp;</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; waveOutMessage(&lt;DeviceID | hWaveOut &gt;, MM_WOM_FORCESPEAKER, bSpeaker, 0);<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">The first parameter can be either a Device ID (e.g. 0 through N-1 if there are N devices in the system), or the handle of an open wave device.&nbsp;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">The third param tells the driver whether to route sound to the speaker (TRUE) or not (FALSE).<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">If param1 is a wave handle (and bSpeaker is TRUE), the sound will be routed to the speaker until you either call the API again with the same handle and bSpeaker==FALSE, or you close the wave handle (or your app exits). If an application calls this API with bSpeaker==FALSE, audio should be routed to the earpiece rather than the speaker.</SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">If param1 is a&nbsp;device ID and bSpeaker==TRUE, all audio is routed to the speaker until there's a matching call to the API with that device ID and bSpeaker==FALSE. This behavior will persist even if the application that made the original call exits. We generally never use this form of the API.<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>Other&nbsp;design details:</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p></o:p></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>-&nbsp;&nbsp;<SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'">This API is more of a hint than a command to the driver. It’s up to the OEM to decide how to interpret this message; we don’t place any requirements on how it is interpreted. Some drivers might just ignore it.</SPAN></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"></SPAN></o:p></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>- The sample driver does a pretty good job of refcounting which steams have enabled the speaker, so if you turn the speaker on twice for a specific stream it won't really do any harm (we'll ignore the second call). </o:p></SPAN></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"></SPAN></o:p></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p></o:p></SPAN></o:p></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>- If multiple streams are playing and only one of them has turned the speaker on, all of the streams will be routed out the speaker until the stream that turned it on either goes away or turns it back off. As an example, if you're listening to music over WMP and an&nbsp;a ringtone gets played,&nbsp;while the incoming ring is being played you may hear both the incoming ring <U>and</U> the music being played through the speaker. If this is objectionable, OEMs may choose to mute (in software) these other streams for the duration that the ringtone&nbsp;is being played over the speaker. </o:p></SPAN></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p></o:p></SPAN></o:p></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>- Most of this design is geared toward hardware implementations where a single piece of audio hardware is multiplexed between one or more speakers and headset jacks (which was the only thing available when the API was designed). </o:p></SPAN></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>&nbsp;</o:p></SPAN></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>- The EventSound subsystem (which manages playback of ringtones) keeps track of which tones should be played with ForceSpeaker turned on via a set of reg keys. OEMs can therefore customize which&nbsp;notifications should&nbsp;play over the speaker.</o:p></SPAN></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>&nbsp;</o:p></SPAN></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>- Don't be surprised if this goes away or gets redesigned in some future release; it's really a Smartphone/PPC proprietary feature, and after 7 years it's getting a little long in the tooth.</o:p></SPAN></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p></o:p></SPAN></o:p></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>Feel free to leave feedback (does anyone read this stuff?).</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p></o:p></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>-Andy</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>Responses to questions:</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>1.&nbsp;Where is MM_WOM_FORCESPEAKER defined?</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>- It should be in audiosys.h, but that might have moved around a bit. The definitions you're looking for are:</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p><FONT face="courier new,courier">&nbsp;&nbsp;&nbsp; #define MM_WOM_SETSECONDARYGAINCLASS<SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>(WM_USER)<o:p></o:p></FONT></P>
<P class=MsoPlainText style="MARGIN: 0in 0in 0pt"><FONT face="courier new,courier">&nbsp;&nbsp;&nbsp; #define MM_WOM_SETSECONDARYGAINLIMIT<SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>(WM_USER+1)<o:p></o:p></FONT></P>
<P class=MsoPlainText style="MARGIN: 0in 0in 0pt"><FONT face="courier new,courier">&nbsp;&nbsp;&nbsp; #define MM_WOM_FORCESPEAKER<SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>(WM_USER+2)</FONT></P><FONT size=3><FONT face=Consolas><o:p>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"><o:p>Keep in mind that these are very likely to change or go away in future release of the operating system.</o:p></SPAN></P></o:p></FONT></FONT>
<P class=MsoPlainText style="MARGIN: 0in 0in 0pt"><o:p><FONT face=Consolas size=3>&nbsp;</FONT></o:p></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt" mce_keep="true">&nbsp;</P></o:p></SPAN>]]></content:encoded>
    </item>
    <item>
      <title>Multichannel Audio in Windows CE</title>
      <link>https://docs.microsoft.com/archive/blogs/medmedia/multichannel-audio-in-windows-ce</link>
      <pubDate>Tue, 16 Jan 2007 12:55:00 GMT</pubDate>
      <dc:creator><![CDATA[Andy Raffman]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/medmedia/2007/01/16/multichannel-audio-in-windows-ce/</guid>
      <description><![CDATA[Most of the infrastructure is in place to support multichannel audio in Windows CE, although the...]]></description>
      <content:encoded><![CDATA[<P>Most of the infrastructure is in place to support multichannel audio in Windows CE, although the number of components that we ship to actually implement it is limited. In this blog I'll cover the varying types of multichannel audio and what features are in place in Windows CE to support it. 
<P>For the purposes of this blog I'll define multichannel audio to mean any audio stream containing more than two channel stereo.&nbsp;We'll further subdivide multichannel audio into three types, differentiated by how the audio data gets from your CE device (e.g. Set Top Box, Smartphone/PPC, whatever) to your receiver: 
<P>1. <STRONG>Analog Matrix Decoders</STRONG>:&nbsp;In this type of decoding, multichannel audio is sent as&nbsp;left/right stereo&nbsp;data to the receiver. In a simple stereo receiver the audio can still be played through left and right speakers and will sound more-or-less correct. However, a receiver supporting the appropriate decoder can use cues placed in the audio to decode to more than two speakers and synthesize additional channels. The most well known&nbsp;decoders are Dolby Pro Logic and Pro Logic II. 
<P>2. <STRONG>Compressed audio over S/PDIF</STRONG>: S/PDIF was originally designed to support a maximum of 4 decompressed PCM channels. While one might use this to pass four discrete audio signals to a receiver, today's multichannel content typically has at least six channels (e.g. 5.1). There's no way to squeeze 6 decompressed audio channels across S/PDIF. The solution to this has been to pass the compressed audio over S/PDIF and let the receiver decompress it (as long as the compressed data bandwidth is less than that which would be required for four decompressed channels). Apart from enabling use of a single cable from the device to&nbsp;the receiver, this has the added benefit of offloading the audio decompression processing into the receiver. The downside of this architecture is that it relies on the receiver to be able to correctly decode the audio data. This is complicated because S/PDIF is a&nbsp;one-way transmission mechanism, so there's no way to query the receiver at runtime to determine what it supports. There are potential timing/latency issues with lip synch. 
<P>Transferring compressed audio over S/PDIF typically involves massaging the compressed audio into a format that matches the S/PDIF frame format <BR>(e.g. by padding the data with zero's as needed) and adding some header information that lets the receiver figure out that you're sending a <BR>compressed audio stream rather than PCM. Both WMAPro and Dolby AC3 have a spec for this. Almost every receiver in the world supports AC3 <BR>decoding. A small (but a growing number) also support WMAPro (Pioneer in particular have spread WMAPro support to even the low end of their product line).</P>
<P>Info on WMAPro is here: <BR><A href="http://download.microsoft.com/download/5/b/5/5b5bec17-ea71-4653-9539-204a672f11cf/wmadrv.doc">http://download.microsoft.com/download/5/b/5/5b5bec17-ea71-4653-9539-204a672f11cf/wmadrv.doc</A></P>
<P>Info on AC3-over-S/PDIF&nbsp;is here in Appendix B: <BR><A href="http://www.dolby.com/assets/pdf/tech_library/46_DDEncodingGuidelines.pdf" target=_blank rel=nofollow mce_href="http://www.dolby.com/assets/pdf/tech_library/46_DDEncodingGuidelines.pdf"><FONT color=#0000cc>http://www.dolby.com/assets/pdf/tech_library/46_DDEncodingGuidelines.pdf</FONT></A> <BR><BR>3. <STRONG>Multiple discrete audio outputs</STRONG>: In this type of connection multiple PCM audio channels are sent to the receiver. Until recently this has meant a separate RCA cable for each channel: a six channel (e.g. 5.1) signal would require six cables between components. HDMI has the potential to&nbsp;overcome this limitation by supporting 6 or more decompressed audio channels (and video) via a single cable.</P>
<P>Outputting to 6 DAC channels presumes that you've already&nbsp;got decompressed multichannel content or you've got a compressed multichannel content that is going to get decompressed before being sent to the wave driver (e.g.&nbsp;AC3 or WMAPro).&nbsp;The latter case is most likely, which means you'll need the appropriate DirectShow decompression filter for CE.<BR></P>
<P>Now, on to what CE supports (and doesn't):&nbsp; </P>
<P><STRONG>Device Drivers</STRONG>&nbsp; 
<P>If you want to support either S/PDIF or multiple discrete audio channels,&nbsp;you&nbsp;should probably want to start with the Ensoniq wavedev2 sample driver that <BR>shipped in the <A class="" title="Windows CE 5.0 Networked Media Device Feature Pack" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=bf17d6b0-4716-494b-9018-7deee9b91832&amp;DisplayLang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=bf17d6b0-4716-494b-9018-7deee9b91832&amp;DisplayLang=en">Windows CE 5.0 Networked Media Device Feature Pack</A> for CE 5 under public\fp_nmd\common\oak\drivers\wavedev\wavedev2\ensoniq. (Note: everything in this feature pack was rolled forward to CE6 as well, so there's nothing in the feature pack that isn't available in CE6 as well, although it might be in a different place). 
<P>This version of the Ensoniq driver has S/PDIF support built into it (the Ensoniq 1371 chip has a sort-of-undocumented S/PDIF mode which we <BR>take advantage of), and supports passing WMAPro-over-S/PDIF compressed date. Support for AC3-over-S/PDIF would be a fairly trivial modification.</P>
<P>One other issue with passing compressed data over S/PDIF is that&nbsp;since the data isn't decompressed to PCM until it gets to your <BR>receiver, there's no way for you to programatically control the volume or mix it with other PCM audio data. The former isn't really a big <BR>issue (the user can always control the volume on their receiver). The latter doesn't have a really great solution. </P>
<P>In the sample Ensoniq driver, whenever we're playing compressed WMAPro out the S/PDIF port we just throw away any PCM data that we're asked to <BR>play so it's never heard (although we maintain the appropriate playback timing, so from the application standpoint everything appears to behave as expected). </P>
<P>To support multichannel discrete outputs in the wave driver one would need to modify the driver to accept a WAVEFORMATEX structure which looks like a normal PCM format but for which the nChannels field is 6 (or more). This is not be a trivial exercise, but should be pretty straightforward. As part of this, for wavedev2 one would have to rewrite the output.cpp file to add a new output stream class that accepts 6 streams, and modify the render functions that handle sample-rate-conversion to support all 6 channels. </P>
<P>Note that the kernel software mixer only supports stereo streams, so it won't do any multichannel mixing for you. This is one reason wavedev2 is probably a good starting place, as it already has code built into it to mix stereo streams which could be extended to&nbsp;more channels.</P>
<P><STRONG>DirectShow Filters</STRONG></P>
<P>DirectShow is Windows CE's media processing infrastructure. The&nbsp;architecture is media-type agnostic, meaning that there's nothing in the overall design that makes it support one type of media any better than another. A number of outside customers are working on multichannel audio products using their own DirectShow filters&nbsp;(or filters they licensed from third-parties). The description below only discusses what Microsoft currently ships with CE5 and CE6.&nbsp;</P>
<P>WMAPro-over-SPDIF filter: The abovementioned&nbsp;Feature Pack also includes a WMAPro-over-SPDIF DirectShow filter to massage WMAPro data into a format which can be sent over S/PDIF. Used in conjunction with a wave driver that supports WMAPro-over-SPDIF content and a receiver which supports decoding WMAPro, this allows a the best decoding quality and performance. To be honest, this isn't currently a terribly common scenario given the limited&nbsp;WMAPro receiver penetration in the market; we did this partly as a proof-of-concept, partly to support our own (Microsoft) technology, and partly because all the pieces were available to us within the company so it wasn't a major development effort. In addition, the&nbsp;architecture and driver changes are applicable to other more common formats (e.g. AC3);&nbsp;although we don't currently ship any explicit support for AC3 streams, OEMs have implemented AC3 support using a similar set of components based on some of this work.</P>
<P>WMAPro decoder: Windows CE includes a WMAPro decoder to decode 5.1, 6.1, and 7.1 compressed content.&nbsp;However, when CE5 was first shipped all our existing customers&nbsp;were still using stereo outputs, so there was&nbsp;no value in passing the discrete channels down to the wave driver. Therefore, while the version that shipped in CE5 decodes all the discrete channels internally, it downmixes them to stereo for output. Therefore, there is currently no way to get the discrete channels out of the WMAPro decoder. The NMD feature pack improved on this situation by introducing matrix-encoding into downmix algorithm: a receiver supporting&nbsp;Pro Logic or Pro Logic II should be able to make use of this information to partially regenerate the discrete channels which were lost during the downmix. We'll look into improving this situation if there's sufficient customer demand. </P>
<P>Dolby AC3: Dolby AC3 is &nbsp;probably the most common/popular multichannel format. Microsoft doesn't currently ship a Dolby AC3 Directshow decoder, although there are probably lots of third party companies that produce such a thing and there may be open source versions (google "ac3filter"). <BR></P>
<P>That's all I've got for now. Please let me know if you found this useful, if there were any errors, or if you have any questions.</P>
<P mce_keep="true">Responses to comments (if I misunderstood anyone's question, please let me know):</P>
<P mce_keep="true">1. How can I playback audio content&nbsp;simultaneously to both&nbsp;analog audio jacks and S/PDIF (Ianbing)</P>
<P mce_keep="true">If I understand correctly, you're trying to play the same audio content over two connections simultaneously (one RCA analog audio jack, and one S/PDIF jack). Assuming that's correct:<BR>- If your audio hardware can simultaneously send a single audio stream over both connections, have the audio driver handle it internally and just expose a single device at the waveapi level.<BR>- If you have two separate pieces of audio hardware (one to handle analog, the other for S/PDIF), you'll need to split the PCM output of the decoder (using a Tee filter- I think there's one under public\directx\sdk\samples\dshow\filters\inftee) and hook both outputs of the tee to the wave renderer. </P>
<P mce_keep="true">The latter design causes an additional problem because you'll need a way to tell each renderer which audio device to playback to. To do this, you'll need to hand-construct the graph, get pointers to each of the two audio render filters, and tell&nbsp;each wave renderer&nbsp;which device ID to play to. I don't believe I've ever tried this, but it should be possible by creating an IPropertyBag object (I think you'll have to roll-your-own, but it's not too difficult), setting the "WaveOutId" property to the ID you want to use, and pass that propertybag to the IPersistProperty interface on the wave renderer.</P>
<P mce_keep="true">Your code would look something like this (sorry, I haven't compiled/tested this):</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT face="courier new,courier" size=2>&nbsp;&nbsp;&nbsp;&nbsp;// CPropertyBag is your implementation of the IPropertyBag interface. </FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT face="courier new,courier" size=2>&nbsp;&nbsp;&nbsp; // We might have a public sample&nbsp;of this (search for cpropertybag.cpp), but I'm not sure</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p><FONT face="courier new,courier" size=2>&nbsp;&nbsp;&nbsp; CPropertyBag PropertyBag;</FONT></o:p></SPAN></P><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p><FONT size=2>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p><FONT size=2>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p><FONT size=2>&nbsp;&nbsp;&nbsp; // Setup your desired device ID</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p><FONT face="courier new,courier" size=2>&nbsp;&nbsp;&nbsp; VARIANT var;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT face="courier new,courier"><FONT size=2>&nbsp;&nbsp;&nbsp; var.vt = VT_I4;</FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT face="courier new,courier"><FONT size=2>&nbsp;&nbsp;&nbsp; var.lVal = &lt;desired device ID&gt;;</FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p><FONT face="courier new,courier" size=2>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p><FONT face="courier new,courier" size=2>&nbsp;&nbsp;&nbsp; // Write the desired ID to your property bag</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT size=2><FONT face="courier new,courier">&nbsp;&nbsp;&nbsp; PropBag.Write( L"WaveOutId", &amp;var ));</FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT size=2></FONT></SPAN>&nbsp;</P></FONT></o:p></SPAN>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT face="courier new,courier" size=2>&nbsp;&nbsp;&nbsp; // Find the waveout renderer in the graph that you want to talk to...</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT size=2>&nbsp;&nbsp;&nbsp; ...</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT face="courier new,courier"></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT face="courier new,courier" size=2>&nbsp;&nbsp;&nbsp; // QI for the IID_IPersistPropertyBag interface... something like this...</FONT></SPAN></P><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT face="courier new,courier"><FONT size=2>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT face="courier new,courier"><FONT size=2>&nbsp;&nbsp;&nbsp; IPersistPropertyBag *pPersistPropertyBag = NULL;<o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt">&nbsp;&nbsp;&nbsp; pWaveOutFilter-&gt;QueryInterface(IID_IPersistPropertyBag, (void **)&amp;pPersistPropertyBag);<o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><o:p><FONT face="courier new,courier" size=2>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT size=2><FONT face="courier new,courier">&nbsp;&nbsp;&nbsp; // Pass the property bag into the wave renderer</FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"><FONT face="courier new,courier"><FONT size=2>&nbsp;&nbsp;&nbsp; pPersistPropertyBag-&gt;Load( &amp;PropBag, NULL );<o:p></o:p></FONT></FONT></SPAN></P>
<P mce_keep="true"><FONT face="courier new,courier"></FONT>
<P mce_keep="true">Deep inside the Load call, the waveout renderer will do something like this with the PropBag pointer you passed in:</P>
<P mce_keep="true"><FONT face="courier new,courier">&nbsp;&nbsp;&nbsp; VARIANT var;<BR>&nbsp;&nbsp;&nbsp; var.vt = VT_I4;<BR>&nbsp;&nbsp;&nbsp; HRESULT hr = pPropBag-&gt;Read(L"WaveOutId", &amp;var, 0);<BR>&nbsp;&nbsp;&nbsp; if(SUCCEEDED(hr))<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_iWaveOutId = var.lVal;<BR>&nbsp;&nbsp;&nbsp; }<BR></FONT></P>
<P mce_keep="true">&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>Windows CE Audio: What does the term "mixer" mean?</title>
      <link>https://docs.microsoft.com/archive/blogs/medmedia/windows-ce-audio-what-does-the-term-mixer-mean</link>
      <pubDate>Fri, 12 Jan 2007 15:14:00 GMT</pubDate>
      <dc:creator><![CDATA[Andy Raffman]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/medmedia/2007/01/12/windows-ce-audio-what-does-the-term-mixer-mean/</guid>
      <description><![CDATA[In the Windows CE audio stack, the term "mixer" is used to refer to a couple of different, unrelated...]]></description>
      <content:encoded><![CDATA[<P>In the Windows CE audio stack, the term "mixer" is used to refer to a couple of different, unrelated components. This blog will try to define each of them and how they differ.</P>
<P>There are usually three different contexts in which "mixer" is used: the "Software Mixer", the "WaveDev2 Mixer", and the "Mixer API". </P>
<P mce_keep="true"><STRONG>The "Software Mixer"</STRONG></P>
<P mce_keep="true">Inside the waveapi module there is a software mixer, sometimes also called the "kernel mixer", which can be used to mix and sample-rate-convert multiple PCM audio output streams. This software mixer was added in CE 4.2 to allow&nbsp;audio drivers which only support one output stream to automagically support multiple concurrent streams at different sampling rates. </P>
<P mce_keep="true">Internally, the software mixer spins off a thread for each wave device to which it's attached. This thread takes application audio buffers and mixes them together into a set of mixer buffers which are then passed down to the audio driver. During this process the software mixer performs these tasks:</P>
<UL>
<LI>
<DIV mce_keep="true">Converts all data to a common 16-bit 2-channel (stereo) format. <BR><BR>Note that this means that for an audio driver to work with the software mixer it <U>must</U> support 16-bit stereo data. If your underlying hardware only supports mono data and you want to make use of the software mixer, your audio driver&nbsp;will need to accept the stereo data and mix it down internally to mono. In this scenario if an application passes mono data down through the stack, the software mixer will&nbsp;duplicate it&nbsp;to the two audio channels and the driver will then remerge the data: not elegant, but the typical performance impact is trivial.<BR><BR>The mixer only supports application buffers with PCM formats of&nbsp;8/16 bit samples and mono/stereo channels. The software mixer can't handle compressed data and can't handle multichannel (e.g. 5.1) PCM data. If you need the software mixer to play any of these formats, they need to be converted to something the mixer understands (e.g. 16-bit stereo PCM) first. This is typically done at the DShow or ACM level, above the software mixer. It only becomes an issue if you want to pass compressed or multichannel audio to the driver. When the software mixer sees a format it doesn't recognize or support, it steps out of the way and passes the waveOutOpen request directly to the device driver. At that point it's totally up to the driver to decide how to handle the request.<BR><BR></DIV></LI>
<LI>
<DIV mce_keep="true">Sample-rate-converts all data to whatever sample rate the driver requires. <BR><BR>The sample-rate-converter is currently a 5-point FIR. Without going into too much detail, the quality and performance have historically been a fairly good tradeoff for most devices, although there's certainly work we'd like to do in the future to improve the quality and performance.<BR><BR>Note that to do the sample rate conversion the mixer needs to know what sample rate the wave driver requires (or pick a reasonable default). I'll cover how this works in another blog entry, along with other configuration details and some more info about the internal design.<BR><BR></DIV></LI>
<LI>
<DIV mce_keep="true">Performs per-stream gain control. <BR><BR>When an application calls waveOutSetVolume and passes a wave handle, the software mixer absorbs the call and handles this, so it will never be seen by the driver (the driver will still see waveOutSetVolume calls using a device ID though).<BR><BR></DIV></LI>
<LI>
<DIV mce_keep="true">Implements support for waveOutSetRate.</DIV></LI></UL>
<P mce_keep="true"><STRONG>The "WaveDev2 Mixer"</STRONG></P>
<P mce_keep="true">The WaveDev2 sample wave driver includes its own output mixer to mix PCM wave streams. This mixer performs basically the same function as the software mixer. Why do we have more-or-less the exact same feature in two different places? You can read&nbsp;my blog <A id=ctl00___ctl00___ctl01___Results___postlist___EntryItems_ctl03_PostTitle href="http://blogs.msdn.com/medmedia/archive/2007/01/03/windows-ce-audio-driver-samples.aspx" mce_href="http://blogs.msdn.com/medmedia/archive/2007/01/03/windows-ce-audio-driver-samples.aspx"><FONT color=#0000cc>Windows CE Audio Driver Samples</FONT></A> for more background, but basically because:</P>
<UL>
<LI>
<DIV mce_keep="true">The waveapi software mixer didn't exist at the time WaveDev2 was developed (it first ran on CE 3.0).</DIV></LI>
<LI>
<DIV mce_keep="true">The WaveDev2 mixer handles some proprietary calls that Smartphone/PPC need (see <A id=ctl00___ctl00___ctl01___Results___postlist___EntryItems_ctl01_PostTitle href="http://blogs.msdn.com/medmedia/archive/2007/01/04/the-wavedev2-gainclass-implementation.aspx" mce_href="http://blogs.msdn.com/medmedia/archive/2007/01/04/the-wavedev2-gainclass-implementation.aspx"><FONT color=#0000cc>The Wavedev2 Gainclass Implementation</FONT></A>). Someday we might fold those into the software mixer, but it hasn't happened yet.</DIV></LI>
<LI>
<DIV mce_keep="true">The WaveDev2 mixer uses a less-cpu-intensive linear interpolation algorithm to perform mixing, and runs in the context of the driver's IST rather than a separate thread. This yields better performance in terms of CPU bandwidth, battery life, and latency (all of which are really important on battery-powered mobile devices).</DIV></LI></UL>
<P mce_keep="true">Having the same feature in two different places and with slightly different/incompatible feature sets is generally not a good thing. Someday we'll&nbsp;rationalize this&nbsp;situation so the mixer only exists in one place.</P>
<P mce_keep="true">The WaveDev2 sample driver also supports "input mixing"; this isn't really mixing, but it allows a single hardware input stream to be split and sample-rate-converted to multiple input clients. I'm including it here because inside the driver it shares the same architecture and alot of the same code paths.</P>
<P mce_keep="true">The other difference between the Software Mixer and&nbsp;the&nbsp;WaveDev2 Mixer is that the former is in private code and isn't generally modifiable by OEMs, while the latter, being part of the OEM device driver, may be modified as needed. This can be a good or bad thing (depending on your desire to change the code and your expertise at not breaking it ;-)</P>
<P mce_keep="true"><STRONG>The "Mixer API"</STRONG></P>
<P mce_keep="true">While the Software Mixer and WaveDev2 MIxer are concerned with mixing PCM audio streams coming down through the Wave API, there's a totally different and unrelated thing called the "Mixer API". </P>
<P mce_keep="true">The Mixer API is an API which conceptually sits alongside other top-level APIs like the Wave API, ACM API, TAPI API, etc. The role of the Mixer API is to expose various low-level audio-related controls&nbsp;at the application level (e.g. things like volume, bass/treble, surround sound, etc.). When someone talks about the Mixer API, they're talking about the set of APIs including mixerOpen, mixerClose, etc. An MSDN reference page is here <A href="http://msdn2.microsoft.com/en-us/library/ms705739.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms705739.aspx">http://msdn2.microsoft.com/en-us/library/ms705739.aspx</A>, and there are some interesting discussions of the Mixer API here <A class=l onmousedown="return clk(this.href,'','','res','1','')" href="http://www.borg.com/~jglatt/tech/mixer.htm" mce_href="http://www.borg.com/~jglatt/tech/mixer.htm"><B><FONT color=#551a8b>Mixer API</FONT></B></A>&nbsp;and here <A class=l onmousedown="return clk(this.href,'','','res','6','')" href="http://blogs.msdn.com/larryosterman/archive/2005/06/14/428962.aspx" mce_href="http://blogs.msdn.com/larryosterman/archive/2005/06/14/428962.aspx"><FONT color=#551a8b>Larry Osterman's WebLog : Mapping audio topologies to mixer topologies</FONT></A>, </P>
<P mce_keep="true">I believe the mixer API was first introduced as part of the Windows Sound System (WSS) DDK. The Windows Sound System was a hardware reference design that Microsoft&nbsp;developed in the early 1990's to evangelize audio hardware support on the PC platform. One of the features of WSS was inclusion of a Crystal Semiconductor 4231 codec, which eventually evolved into the AC'97 codec spec. This codec had a number of hardware mixing and volume control&nbsp;features to support multiple inputs and outputs (<A class=l onmousedown="return clk(this.href,'','','res','3','')" href="http://web.mit.edu/afs/sipb/contrib/doc/specs/ic/audio/cs4231a.pdf"><FONT color=#551a8b>cs4231a multimedia audio codec</FONT></A>), but there was no API defined to allow applications to access them. Thus was born the mixer API.</P>
<P mce_keep="true">The Mixer&nbsp;API was designed to allow a mixer application with no knowledge of the underlying audio architecture to create interactive UI&nbsp;for the end user. As a consequence, the Mixer API allows the application to query information suggesting what type of UI element to use to represent a control (e.g. a pushbutton, slider, multiple-select, etc.), and even query the labels that the application should display. On the desktop windows, when you run SndVol32 to bring up the mixer control panel (which uses the desktop's implementation of Mixer API), remember that SndVol32 has absolutely no a priori knowledge of what your soundcard supports. All those labels and controls are derived by calling down to the driver level.</P>
<P mce_keep="true">All MixerAPI calls into the audio device driver&nbsp;are done via an IOCTL_MIX_MESSAGE IoControl.&nbsp;An audio driver can add support for the mixer API by adding support for this call and the myriad messages that route through it. Although&nbsp;Windows CE audio sample drivers typically include sample code to support for the mixer API, in general it's an optional part of the wave driver and&nbsp;there are&nbsp;very few&nbsp;applications that make use of&nbsp;it (although there are some, notably VoIP).</P>
<P mce_keep="true">&nbsp;</P>]]></content:encoded>
    </item>
  </channel>
</rss>