[WiP] TV Server hardware-specific code refactoring (1 Viewer)

mm1352000

Retired Team Member
  • Premium Supporter
  • September 1, 2008
    21,577
    8,224
    Home Country
    New Zealand New Zealand
    Developers - I need some help/advice!

    My original goal was to enable DiSEqC to work on my Pinnacle PCTV 7010ix (see this thread). This relatively small goal has got a little out of hand :oops:

    ---------------------------------------------------------------------
    My card uses the default GenericBDA DiSEqC handler. The only reason why the existing version of the handler doesn't work is that the driver for my card requires the DirectShow put_Range() function to be called *after* the graph is started. In other words, the call to ConditionalAccess.SendDiseqCommand() must be made after the call to ((IMediaControl)_graphBuilder).Run(). Obviously some cards work just fine with the existing handler - I don't want to mess that up! However I'm sure there are other cards just like mine so I thought it would be helpful to the community to create a patch that calls the SendDiseqCommand() function again after the graph has started if the first call fails and the handler is the GenericBDA handler. This would be similar to the existing hack-fix for Hauppauge cards (except the graph shouldn't be restarted)...

    I thought creating a patch would be easy until I started getting deeper into the ConditionalAccess and hardware-specific code. The DiSEqC code within the hardware-specific classes seemed to be quite unstructured and this made it difficult to quickly make my patch. I decided to do "a little" ***careful*** refactoring to make my job easier. I finally finished what I thought was reasonable this evening, however "a little" had turned into *way more* than I intended. You can see what I have done in the attached patch...

    Summary:
    - I extended and modified the existing IHardwareProvider interface and created a HardwareProviderBase abstract class that all the hardware specific classes (except the SS2) now override. This means all the hardware-specific classes now have base properties/functionality such as a "provider name" (eg. "Hauppauge") and a list of capabilities (eg. CAM, DiSEqC switching, DiSEqC motor control). It also makes the ConditionalAccess constructor code much simpler.
    - I extended the IHardwareProvider interface with a further IDiSEqCPortController interface. All hardware providers that support DiSEqC switching now implement this interface. Because many of the hardware specific classes had similar code for port switching I also created a base abstract DiSEqCPortControllerBase class with the generic port switching code from the GenericBDA handler.
    - I extended the IDiSEqCPortController with a further IDiSEqCController interface. All hardware providers that support sending generic DiSEqC commands (for DiSEqC motor control) now implement this interface. Again, much of the hardware specific code for sending DiSEqC port commands was very similar so I created a DiSEqCControllerBase class to implement default port switching behaviour.
    - I also created two other interfaces - IQAMHardwareProvider and IDVBS2HardwareProvider - which extend the IHardwareProvider interface. Hardware which support ATSC tuning and DVB-S2 tuning implement these interfaces.

    What I have not done yet that could also be done is to create an interface for devices that have CI/CAM functionality...

    After all that work I confess I am a quite afraid that you will reject my refactoring simply because the affected code is "mission critical" or that changes to this area of the code are out of scope at the moment. I urge you to take time to consider what I have done - I think what I have done is a huge improvement to the structure of the code. I have also been ***very*** careful to ensure that I don't make changes where changes don't need to be made to try to avoid breaking existing functionality.

    Thank you for your consideration

    ---------------------------------------------------------------------
    Update: 2010-10-08

    I now have a patch which is not a hack! It supports the 7010ix using a special provider which inherits from the generic provider. Only specific hardware is supported by the provider (at present only the 7010ix). Hardware is identified by device path. My thanks to romadd64 and elorentz :) The new version of the patch (built on SVN HEAD) is attached to this post.

    ---------------------------------------------------------------------
    Update: 2010-10-09

    Patch and DLLs for 1.1.0 final as requested by romadd64 are now also available.
    DLLs = TVLibrary[1.1.0_SVN_26097].zip
    Code patch = HardwareSpecificCodeRefactoring(v2)[1.1.0_SVN_26097].zip

    ---------------------------------------------------------------------
    Update: 2010-10-13

    Patch and DLLs for 1.1.1 final as requested by ColinT (see this thread). I have also made a few more changes:
    - add the BGT3595 HWID to the BlackgoldBDA handler to support ColinT's card
    - remove the Init() function from the IHardwareProvider interface. I think it is much safer to have all initialisation happen in the constructor - no chance of forgetting to call Init(). This required the constructors for all the hardware providers to be given an additional parameter (device path).
    - use a common base class variable for IsSupported and remove a couple of other unnecessary class variables here and there in the other providers
    - don't attempt to send DiSEqC commands for DVB-T cards (BlackgoldBDA handler)
    - fix for Digital Devices provider (*only* 1.1.1 and SVN HEAD). The CI/CAM thread was not being stopped/disposed when the hardware provider is disposed :eek:. This is an issue with the current code (not just my refactoring) so it could be added as a separate fix if necessary.

    ---------------------------------------------------------------------
    Update: 2010-10-28

    New patches and DLLs for 1.1.0, 1.1.1 and SVN 26615. Changes:
    - fix Blackgold BGT3595 HWID
    - add Pinnacle PCTV 710ix
    - provide a proper build for 1.1.1 (thanks NTAuthority :))

    This build (v4) does not have any CI/CAM refactoring.

    ---------------------------------------------------------------------
    Update: 2010-11-28

    New patches and DLLs for 1.1.0, 1.1.1 and SVN 26867. Changes:
    - add Blackgold BGT3540 HWID to support DiSEqC switching for that card
    - new interface ICamController and refactoring of CI/CAM control code to implement it
    - new interface IAddOnDevice and refactoring of WinTV CI and DigitalDevices code to implement it.
    - integrate IAddOnDevice in ConditionalAccess and TvCardDvbBase.

    Still TODO:
    - integrate morpheus_xxx's plugin manager

    This build (v5) has substantial code refactoring in the CI/CAM code. I have been ***very*** careful, but I may have inadvertently broken support for scrambled channels. I'd appreciate it if you could test and help me to find any bugs :)

    ---------------------------------------------------------------------
    Update: 2010-11-29

    Add patch for 1.2.0a.

    ---------------------------------------------------------------------
    Update: 2010-12-10

    Add patch for 1.1.2
     

    Attachments

    • HardwareSpecificRefactoring[v4][1.1.0_SVN_26097].zip
      31.6 KB
    • HardwareSpecificRefactoring[v4][1.1.1_26460].zip
      31.7 KB
    • HardwareSpecificRefactoring[v4][SVN_HEAD_26615].zip
      32.9 KB
    • TVLibrary[v4][1.1.0_SVN_26097].zip
      182.4 KB
    • TVLibrary[v4][1.1.1_26460].zip
      181.6 KB
    • TvLibrary[v4][SVN_HEAD_26615].zip
      185.8 KB
    • HardwareSpecificRefactoring[v5][1.1.0_SVN_26097].zip
      69.3 KB
    • HardwareSpecificRefactoring[v5][1.1.1_26460].zip
      69.3 KB
    • HardwareSpecificRefactoring[v5][SVN_HEAD_26867].zip
      74.3 KB
    • TVLibrary[v5][1.1.0_SVN_26097].zip
      180.8 KB
    • TVLibrary[v5][1.1.1_26460].zip
      181.1 KB
    • TvLibrary[v5][SVN_HEAD_26867].zip
      184.3 KB
    • HardwareSpecificRefactoring[v5][1.2.0a_26637].zip
      74.3 KB
    • TvLibrary[v5][1.2.0a_26637].zip
      184 KB
    • HardwareSpecificRefactoring[v5][1.1.2_26886].zip
      69.3 KB
    • TVLibrary[v5][1.1.2_26886].zip
      181.3 KB
    Last edited by a moderator:

    romadd64

    MP Donator
  • Premium Supporter
  • October 24, 2007
    82
    15
    Home Country
    Italy Italy
    mm1352000,

    I'm not a team developer, but I'm very interested because I have a 7010ix.

    Why not add two functions on provider interface, BeforeGraphDiseqc() and AfterGraphDiseqc(), called before and after the call to ((IMediaControl)_graphBuilder).Run(), that each provider overrides if needed? And the 7010x should have a specific provider instead of using the Generic.

    romadd
     

    mm1352000

    Retired Team Member
  • Premium Supporter
  • September 1, 2008
    21,577
    8,224
    Home Country
    New Zealand New Zealand
    Two points in response to your excellent suggestions:

    ------------------------------------------------------------------------------------------
    1. To be able to create a specialised provider you need to be able to detect the card/s that the provider should handle. In other words, if you want to have a special provider for the 7010ix then you need to be able to detect that the user's card is a 7010ix. This is usually done in two main ways:

    - Detecting availability of specialised functionality through vendor specific driver APIs.
    This requires knowledge that [usually] only the hardware vendor (TBS, Pinnacle, Hauppauge etc.) can provide. In the case of the 7010ix: I have been in contact with PCTV Systems (who took over the Pinnacle's TV card business). They refuse to support the 7010ix because they say it is "obsolete" and apparently it was only sold to OEMs (they only provide support for cards that they sell themselves - "retail" support). Furthermore, the drivers and support were originally provided by NXP (the card's SAA7162 PCI-e bridge chipset manufacturer). Any support that used to be provided was provided by them (NXP). In short, PCTV Systems cannot help with this - they don't have the knowledge. I have tried to contact NXP but have not yet received a reply. To be honest I think it is unlikely that I will get a helpful response. The SAA7162 part was discontinued some time ago and is now EOL/obsolete. Putting all that aside, the fact that I can get DiSEqC to work in the way that I have (using the generic provider) means that there is unlikely to be a vendor specific API anyway.

    - Through the names of the tuners, as given by the driver.
    I don't know about you but I'm actually using the Blackgold BGT3540 drivers for improved stability. My cards' names are very generic - "7162 BDA X Tuner" where X is either DVBS, DVBT or Analog. All we can tell from those names is that the card could be any SAA7162 based card.

    So, in my opinion it would be difficult (if not impossible) to properly detect that the user's card is a 7010ix, which means that we can't really create the custom provider. The only hope for this approach is that NXP provide a helpful reply to my emails.

    ------------------------------------------------------------------------------------------
    2. As I tried to explain in the original post, part of the reason for all the refactoring that I did was to enable me to use callbacks to resend the DiSEqC command. This is the same concept as what you are suggesting ("BeforeGraphDiseqc() and AfterGraphDiseqc()"). In principle there is no problem with this approach, however there are two practical issues:

    - We can't mess up the existing functionality which works for some cards.
    If we always resend the DiSEqC command for the generic provider then we may break DiSEqC for other cards that use the generic provider. This is why it would be better to have a custom provider for the 7010ix like you suggested, but [as I have tried to explain above] that is difficult/impossible.

    - Detect that the DiSEqC command fails and resend after the graph.Run() when it doesn't work.
    This was my preferred approach because it avoids messing up the support for other cards. Furthermore, it also has the potential to improve support for cards that are currently unsupported (Blackgold?, Pinnacle?) that behave like the 7010ix. However [like I explained in my original post] for the 7010ix it is only possible to detect failure to send the DiSEqC command on the first attempt to tune a channel after the graph has been built. Since the graph is built *once* (when a tuner is first used after the TV Server starts/restarts), it would only be possible to correctly resend the DiSEqC command for the first channel that you try to watch. After that you can't detect that the DiSEqC command fails -> you don't resend the command -> the switch doesn't change port ==> TV doesn't work. I actually tested this so you can take my word that it doesn't work...

    ------------------------------------------------------------------------------------------
    What does this all mean? Unfortunately I think it means that the 7010ix cannot be directly supported unless the developers are able to suggest a better approach or allow me to add an option in the TV Server config (to force the DiSEqC command to be sent/resent after the graph is started). This is very sad! :(:(:(

    None of the above stops us from making a custom build for ourselves though ;)
    Did you check out this thread? I have provided custom DLLs for testing with MP 1.1.0. I suggest using the last version from this post.

    Be warned!!! The DLLs work perfectly for me with 2 7010ix cards and an EMP Centauri Profi-Line 9x8 multiswitch. Only one other user has tried them and he reported that his card was somehow damaged (although we both think it was not my DLLs)!

    The other patch that you may be interested in is here - it fixes FM radio support for the 7010ix.

    Finally, I'd like to repeat that I am using Blackgold BGT3540 drivers (version 6.0.0.49 from here) on Windows XP.
     

    romadd64

    MP Donator
  • Premium Supporter
  • October 24, 2007
    82
    15
    Home Country
    Italy Italy
    mm1352000,

    1. I think that to be able to detect the card/s that the provider should handle, you don't need to know their API. Use a different approach. With the card HW ID you can know the card model. 7010x for example is PCI\VEN_1822&DEV_4E35&SUBSYS_1179153B or PCI\VEN_1822&DEV_4E35&SUBSYS_1179153B&REV_01. TVServer already gets this ID for every card at startup, look at the DB in table Cards, field devicePath. Every card model will have a different HW ID, but if you look at the .inf file of the driver, you will find all the ID that it accepts.


    2. Given the solution at 1., it's possible to have a dedicated provider for 7010ix.


    I use the same BlackGold driver, only on Vista X64. However I must admit that it doesn't resolve the standby/resume problem but, disabling the card before standby, it works.

    I'll give a try to your modified TvLibrary.dll for Diseqc.
    I have also another spare 7010ix (no more free PCI slot on server), I can risk frying my card with your mod ;):oops:

    romadd
     

    mm1352000

    Retired Team Member
  • Premium Supporter
  • September 1, 2008
    21,577
    8,224
    Home Country
    New Zealand New Zealand
    Good point. I'll see if I can access the hardware ID. All that I have seen in the present handlers is GUIDs or card names. Perhaps I can query the DB for it using the "business layer"...

    Regarding the patch: I think it is unlikely that it will damage your card as our setups are very similar. Also any interactions with the hardware are through the drivers. The only way a card can be damaged from software is if the drivers are bad, and this would be impossible to know or fix. Let me know how you get on...
     

    romadd64

    MP Donator
  • Premium Supporter
  • October 24, 2007
    82
    15
    Home Country
    Italy Italy
    I have good news.
    My 7010ix is still alive and working well with your modded tvlibrary :D. In my previous post I was joking about frying card ;).
    But it breaks the working Diseqc of the Terratec Cinergy S2 (that doesn't use the generic provider).

    The HW ID should be in the card.DevicePath of ConditionalAccess().

    romadd
     

    mm1352000

    Retired Team Member
  • Premium Supporter
  • September 1, 2008
    21,577
    8,224
    Home Country
    New Zealand New Zealand
    Excellent... and then not so good!

    That patch is a hack specifically to allow the 7010ix to work. At the time I had only partly completed the refactoring that I thought would be necessary and so it is entirely possible that the DiSEqC for other cards is broken. Are you running the latest SVN build?
    I could give you new DLLs that include all my refactoring as well as the hack for the 7010ix and then you should have DiSEqC with both the Terratec and the 7010ix...

    [Edit: alternatively I could revert my SVN build to whatever version you're running, add only my patch, and compile the DLLs for you]

    Regarding HW IDs: I have seen the HW IDs that you mentioned in the MP DB, as well as a function that will retrieve them in the business layer so I will try to put together a special provider or add code to the OnGraphRun() callback of the generic handler.
     

    mm1352000

    Retired Team Member
  • Premium Supporter
  • September 1, 2008
    21,577
    8,224
    Home Country
    New Zealand New Zealand
    romadd64

    My HW IDs are different to yours. The ID from the Pinnacle/PCTV Systems INF file looks like:

    PCI\VEN_1131&DEV_7162&SUBSYS_010111BD

    The Blackgold one is similar but more generic:

    PCI\VEN_1131&DEV_7162

    In the MP DB it looks like:

    @device:pnp:\\?\pci#ven_1131&dev_7162&subsys_010111bd&rev_01#4&4c5e15f&0&00e2#{71985f48-1ca1-11d3-9cc8-00c04f7971e0}\{9bb4f27f-515c-43ca-8e7d-f07c00080002}

    I actually also have an old DigitalNow Quattro S-T (rebadged and perhaps slightly modified Twinhan VP6090/VP6091) which was also an SAA7162 based card. DiSEqC worked for that device using the Twinhan provider. The device IDs for these parts are very similar:

    PCI\VEN_1131&DEV_7162&SUBSYS_00271822 (Twinhan 6090)
    PCI\VEN_1131&DEV_7162&SUBSYS_00321822 (Twinhan 6091)
    PCI\VEN_1131&DEV_7162&SUBSYS_00371822 (DigitalNow Quattro S-T)

    Clearly I am going to have to be careful about which HW IDs I use. Even the subsystem ID may be important. My research says:

    Vendor 1131 is either Philips Semiconductors or Animation Technologies Inc (I think it is Philips/NXP).
    Device 7162 is a reference to their SAA7162 PCIe bridge chipset part.

    I don't understand how your card can have either of the HW IDs you mentioned:

    PCI\VEN_1822&DEV_4E35&SUBSYS_1179153B
    PCI\VEN_1822&DEV_4E35&SUBSYS_1179153B&REV_01

    My research says that this is a Mantis device...
     

    elorentz

    Portal Pro
    July 6, 2006
    58
    2
    Cut and paste job from the net, hope it helps you guys in some way

    The Vendor ID 0x1131 is indeed "Philips Semiconductors", the Device ID 0x7162 is the "saa7162 PCIe Interface".
    The subvendor ID 0x11bd is "Pinnacle Systems Inc." while the subdevice ID 0x0101 is "PCTV 7010iX TV Card"
     

    mm1352000

    Retired Team Member
  • Premium Supporter
  • September 1, 2008
    21,577
    8,224
    Home Country
    New Zealand New Zealand
    Thank you that is very helpful :) Do you mind telling me where you got this information. I need to know what the hardware ID would be for the Blackgold BGT3540.

    FYI I have modified my patch and added a specific provider for the 7010ix called BlackgoldBDA (because we are using Blackgold drivers and because I suspect other Blackgold cards will need to use it):
    - inherits from the GenericBDAS handler
    - detects cards based on the HW ID - currently the only card that will use it is the 7010ix
    - it overrides the base SendDiSEqCPortCommand() with an empty function that returns false so that the DiSEqC functionality is hidden. This means that it does not send a DiSEqC command before the graph is running to avoid the 100ms delay associated with doing this.
    - the mechanism for sending DiSEqC commands is through the provider's IHardwareProvider OnRunGraph() callback. This is always called (by the ConditionalAccess OnRunGraph() callback) immediately after the graph is confirmed to be running. Hardware providers do nothing in this callback by default. However, the BlackgoldBDA handler overrides the base callback and calls the [DiSEqCPortControllerBase] base implementation of SendDiSEqCPortCommand().

    *Most importantly, it actually works!!!* :D:D:D
    I'll post the new code as soon as I can - just got some comments to add.
     

    Users who are viewing this thread

    Top Bottom