├── .gitignore ├── COPYING ├── HISTORY ├── Makefile ├── README ├── common.c ├── common.h ├── config.c ├── config.h ├── detectsatip.py ├── device.c ├── device.h ├── deviceif.h ├── discover.c ├── discover.h ├── discoverif.h ├── log.h ├── msearch.c ├── msearch.h ├── param.c ├── param.h ├── po ├── ca_ES.po ├── de_DE.po ├── es_ES.po ├── fi_FI.po └── pl_PL.po ├── poller.c ├── poller.h ├── pollerif.h ├── rtcp.c ├── rtcp.h ├── rtp.c ├── rtp.h ├── rtsp.c ├── rtsp.h ├── satip.c ├── sectionfilter.c ├── sectionfilter.h ├── server.c ├── server.h ├── setup.c ├── setup.h ├── socket.c ├── socket.h ├── statistics.c ├── statistics.h ├── tuner.c ├── tuner.h └── tunerif.h /.gitignore: -------------------------------------------------------------------------------- 1 | .dependencies 2 | *.o 3 | *.so 4 | *~ 5 | po/*.pot 6 | po/*.mo 7 | .settings 8 | .cproject 9 | .project 10 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Lesser General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /HISTORY: -------------------------------------------------------------------------------- 1 | =================================== 2 | VDR Plugin 'satip' Revision History 3 | =================================== 4 | 5 | 2014-03-08: Version 0.0.1 6 | 7 | - Initial revision. 8 | - Added German translation (Thanks to Frank Neumann). 9 | 10 | 2014-03-15: Version 0.1.0 11 | 12 | - Switched to the standard S/T/C source identifiers. 13 | - Added a new operation mode setup parameter. 14 | - Added new SVDRP commands. 15 | 16 | 2014-03-16: Version 0.1.1 17 | 18 | - Changed code to utilize a proper XML library. 19 | - Refactored the session code. 20 | - Fixed EIT scan functionality. 21 | - Updated for vdr-2.1.6. 22 | 23 | 2014-03-28: Version 0.2.0 24 | 25 | - Added support for cDevice::Ready(). 26 | - Fixed pid leaking while disabling section filters. 27 | - Fixed keepalive heartbeat. 28 | 29 | 2014-04-01: Version 0.2.1 30 | 31 | - Changed implementation to report about RTP packet 32 | errors on 5 minutes interval only. 33 | - Added a check to write new sections only if there 34 | is no data in the read socket. 35 | - Fixed keepalive heartbeat again. 36 | 37 | 2014-04-05: Version 0.2.2 38 | 39 | - Fixed the default keepalive interval. 40 | - Refactored the section filtering. 41 | - Added Catalan translation (Thanks to Gabriel Bonich). 42 | 43 | 2014-04-12: Version 0.2.3 44 | 45 | - Added Spanish translation (Thanks to Gabriel Bonich). 46 | - Fixed parameters of the OPTIONS command. 47 | - Added a device identication into the user agent string. 48 | - Removed unnecessary PLAY commands and header callbacks. 49 | 50 | 2014-04-20: Version 0.3.0 51 | 52 | - Tweaked the pid update mechanism. 53 | 54 | 2014-04-27: Version 0.3.1 55 | 56 | - Fixed the device discovery. 57 | 58 | 2014-05-10: Version 0.3.2 59 | 60 | - Fixed model detection and OctopusNet DVB-C model quirks. 61 | - Added a session id quirk for GSSBOX. 62 | 63 | 2014-05-18: Version 0.3.3 64 | 65 | - Added a validity check for the session member. 66 | - Added a session id quirk for Triax TSS 400. 67 | 68 | 2014-12-24: Version 1.0.0 69 | 70 | - Fixed the cable only device detection. 71 | - Added support for blacklisted sources. 72 | - Fixed server reuse for active transponders. 73 | - Added a preliminary support for Fritz!WLAN 74 | Repeater DVB-C (Thanks to Christian Wick). 75 | - Added a preliminary support for Telestar 76 | Digibit R1 (Thanks to Dirk Wagner). 77 | - Added a new device status menu. 78 | - Added support for SAT>IP frontend selection via 79 | Radio ID. 80 | - Added command-line switches for manually defining 81 | used SAT>IP servers and setting used tracing mode. 82 | - Added new STAT and TRAC commands into the SVDRP 83 | interface. 84 | - Refactored the tuner implementation. 85 | - Updated against SAT>IP protocol specification 86 | version 1.2.1. 87 | - Refactored input thread to increase performance. 88 | - Added plenty of performance tweaks (Thanks to 89 | Stefan Schallenberg). 90 | - Fixed EIT scan (Thanks to Stefan Schallenberg). 91 | 92 | 2015-01-10: Version 1.0.1 93 | 94 | - Updated the command-line help and README. 95 | - Fixed the server teardown. 96 | - Removed the unnecessary config directory definition. 97 | - Added a fallback for older glibc libraries. 98 | - Improved pid selection performance. 99 | - Added support for Digital Devices CI extension. 100 | 101 | 2015-01-18: Version 1.0.2 102 | 103 | - Added configurable CI slots. 104 | - Fixed parsing of the setup values. 105 | - Added an option to disable sources via sources.conf. 106 | - Added a command-line option to disable all the 107 | SAT>IP server quirks. 108 | - Updated Spanish and Catalan translations (Thanks to 109 | Gabriel Bonich). 110 | - Updated German translations (Thanks to Frank Neumann). 111 | 112 | 113 | =================================== 114 | VDR Plugin 'satip' Revision History 115 | =================================== 116 | 117 | 2015-02-19: Version 2.2.0 118 | 119 | - Updated for vdr-2.2.0. 120 | - Fixed memory deallocation errors. 121 | - Cleaned up all scan-build warnings. 122 | - Refactored the frontend handling. 123 | 124 | 2015-04-04: Version 2.2.1 125 | 126 | - Improved RTSP error checking. 127 | - Got rid of SATIP_DEBUG. 128 | - Robustify the server discovery. 129 | - Fixed a memory leak in TinyXML implementation 130 | (Thanks to Oliver Endriss). 131 | - Updated against SAT>IP protocol specification 132 | version 1.2.2. 133 | 134 | 2015-04-26: Version 2.2.2 135 | 136 | - Added a more flexible OPER command in the SVDRP 137 | interface. 138 | - Added new ATTA and DETA SVDRP commands. 139 | - Set the default device count to two. 140 | 141 | 2015-09-18: Version 2.2.3 142 | 143 | - Added a timeout for releasing idling devices. 144 | - Reset the RTSP connection after any failed connect. 145 | - Added tweaks for minisatip and Schwaiger MS41IP. 146 | - Updated for vdr-2.3.1 (Thanks to Klaus Schmidinger). 147 | 148 | 2016-12-18: Version 2.2.4 149 | 150 | - Updated German translation (Thanks to Frank Neumann). 151 | - Fixed Panasonic CXW804 support (Thanks to Tobias Grimm). 152 | - Fixed C++11 support (Thanks to Tobias Grimm). 153 | - Fixed server assigment with source validation (Thanks to Patrick Boettcher). 154 | - Added configurable RTP/RTCP ports (Thanks to chriszero). 155 | - Added support for X-SATIP-RTSP-Port header. 156 | - Added multicast and RTP-over-TCP support. 157 | - Added support for activating/deactivating server on-the-fly. 158 | - Extended command-line parameters for setting server quirks. 159 | 160 | 2017-08-15: Version 2.2.5 161 | 162 | - Added Polish translation (Thanks to Tomasz Nowak). 163 | - Updated Catalan and Spanish translations (Thanks to Gabriel Bonich). 164 | - Added support for KATHREIN SatIP Server (Thanks to kavanu). 165 | - Added support for FRITZ!Box 6490 Cable (Thanks to 9000h). 166 | - Updated FRITZ!WLAN Repeater DVB-C detection for the latest firmware (Thanks to 9000h). 167 | - Added GCC7 compatibility (Thanks to Sascha Kuehndel). 168 | 169 | 170 | =================================== 171 | VDR Plugin 'satip' Revision History 172 | =================================== 173 | 174 | 2016-12-18: Version 2.3.0 175 | 176 | - Updated for vdr-2.3.1. 177 | - Updated German translation (Thanks to Frank Neumann). 178 | - Fixed Panasonic CXW804 support (Thanks to Tobias Grimm). 179 | - Fixed C++11 support (Thanks to Tobias Grimm). 180 | - Fixed server assigment with source validation (Thanks to Patrick Boettcher). 181 | - Added configurable RTP/RTCP ports (Thanks to chriszero). 182 | - Added support for X-SATIP-RTSP-Port header. 183 | - Added multicast and RTP-over-TCP support. 184 | - Added support for activating/deactivating server on-the-fly. 185 | - Extended command-line parameters for setting server quirks. 186 | 187 | 2017-08-15: Version 2.3.1 188 | 189 | - Updated for vdr-2.3.7 (Thanks to Klaus Schmidinger). 190 | - Added Polish translation (Thanks to Tomasz Nowak). 191 | - Updated Catalan and Spanish translations (Thanks to Gabriel Bonich). 192 | - Added support for KATHREIN SatIP Server (Thanks to kavanu). 193 | - Added support for FRITZ!Box 6490 Cable (Thanks to 9000h). 194 | - Updated FRITZ!WLAN Repeater DVB-C detection for the latest firmware (Thanks to 9000h). 195 | - Added GCC7 compatibility (Thanks to Sascha Kuehndel). 196 | 197 | 198 | =================================== 199 | VDR Plugin 'satip' Revision History 200 | =================================== 201 | 202 | 2018-04-15: Version 2.4.0 203 | 204 | - Updated for vdr-2.4.0. 205 | - Removed speed limit. 206 | - Fixed transport media changes. 207 | - Fixed memory leak in cSatipSectionFilter (Thanks to Alexander Pipelka). 208 | - Added more robust section filter handling (Thanks to Alexander Pipelka). 209 | - Added a command line parameter for the RTP receive buffer size (Thanks to Stefan Rehm). 210 | 211 | 2021-06-01: Version 2.4.1 212 | 213 | - Added an option to enable/disable frontend reuse. 214 | - Added a preliminary ATSC support. 215 | - Fixed a channel switching logic bug (Thanks to REELcoder). 216 | - Added a workaround for detecting Panasonic devices. 217 | - Removed quirks from FRITZ!Box 6490 Cable due to new firmware. 218 | - Fixed RTP over TCP. 219 | - Fixed URL parameter creation (Thanks to Martin Janser). 220 | - Added an option to enable/disable frontend reuse. 221 | - Added a preliminary ATSC support. 222 | - Fixed a channel switching logic bug (Thanks to REELcoder). 223 | - Added quirks for Inverto IDL-400s. 224 | - Updated German translation (Thanks to Martin Dummer). 225 | - Added a quirk for always teardown before play (Thanks to maazl). 226 | - Updated for vdr-2.4.3 (Thanks to IP plugin 3 | # 4 | 5 | # Use TinyXML instead of PugiXML 6 | 7 | #SATIP_USE_TINYXML = 1 8 | 9 | # The official name of this plugin. 10 | # This name will be used in the '-P...' option of VDR to load the plugin. 11 | # By default the main source file also carries this name. 12 | 13 | PLUGIN = satip 14 | 15 | ### The version number of this plugin (taken from the main source file): 16 | 17 | VERSION = $(shell grep 'const char VERSION\[\] *=' $(PLUGIN).c | awk '{ print $$5 }' | sed -e 's/[";]//g') 18 | GITTAG = $(shell git describe --always 2>/dev/null) 19 | 20 | ### The directory environment: 21 | 22 | # Use package data if installed...otherwise assume we're under the VDR source directory: 23 | PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell PKG_CONFIG_PATH="$$PKG_CONFIG_PATH:../../.." pkg-config --variable=$(1) vdr)) 24 | LIBDIR = $(call PKGCFG,libdir) 25 | LOCDIR = $(call PKGCFG,locdir) 26 | PLGCFG = $(call PKGCFG,plgcfg) 27 | CFGDIR = $(call PKGCFG,configdir) 28 | # 29 | TMPDIR ?= /tmp 30 | 31 | ### The compiler options: 32 | 33 | export CFLAGS = $(call PKGCFG,cflags) 34 | export CXXFLAGS = $(call PKGCFG,cxxflags) 35 | STRIP ?= /bin/true 36 | 37 | ### The version number of VDR's plugin API: 38 | 39 | APIVERSION = $(call PKGCFG,apiversion) 40 | 41 | ### Allow user defined options to overwrite defaults: 42 | 43 | -include $(PLGCFG) 44 | 45 | ### The name of the distribution archive: 46 | 47 | ARCHIVE = $(PLUGIN)-$(VERSION) 48 | PACKAGE = vdr-$(ARCHIVE) 49 | 50 | ### The name of the shared object file: 51 | 52 | SOFILE = libvdr-$(PLUGIN).so 53 | 54 | ### Libraries 55 | 56 | LIBS = $(shell curl-config --libs) 57 | 58 | ### Includes and Defines (add further entries here): 59 | 60 | INCLUDES += 61 | 62 | DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' 63 | 64 | ifdef SATIP_USE_TINYXML 65 | DEFINES += -DUSE_TINYXML 66 | LIBS += -ltinyxml 67 | else 68 | LIBS += -lpugixml 69 | endif 70 | 71 | ifneq ($(strip $(GITTAG)),) 72 | DEFINES += -DGITVERSION='"-GIT-$(GITTAG)"' 73 | endif 74 | 75 | .PHONY: all all-redirect 76 | all-redirect: all 77 | 78 | ### The object files (add further files here): 79 | 80 | OBJS = $(PLUGIN).o common.o config.o device.o discover.o msearch.o param.o \ 81 | poller.o rtp.o rtcp.o rtsp.o sectionfilter.o server.o setup.o socket.o \ 82 | statistics.o tuner.o 83 | 84 | ### The main target: 85 | 86 | all: $(SOFILE) i18n 87 | 88 | ### Implicit rules: 89 | 90 | %.o: %.c 91 | @echo CC $@ 92 | $(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< 93 | 94 | ### Dependencies: 95 | 96 | MAKEDEP = $(CXX) -MM -MG 97 | DEPFILE = .dependencies 98 | $(DEPFILE): Makefile 99 | $(Q)$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ 100 | 101 | -include $(DEPFILE) 102 | 103 | ### Internationalization (I18N): 104 | 105 | PODIR = po 106 | I18Npo = $(wildcard $(PODIR)/*.po) 107 | I18Nmo = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file)))) 108 | I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) 109 | I18Npot = $(PODIR)/$(PLUGIN).pot 110 | 111 | %.mo: %.po 112 | @echo MO $@ 113 | $(Q)msgfmt -c -o $@ $< 114 | 115 | $(I18Npot): $(wildcard *.c) 116 | @echo GT $@ 117 | $(Q)xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='' -o $@ `ls $^` 118 | 119 | %.po: $(I18Npot) 120 | @echo PO $@ 121 | $(Q)msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $< 122 | @touch $@ 123 | 124 | $(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo 125 | @echo IN $@ 126 | $(Q)install -D -m644 $< $@ 127 | 128 | .PHONY: i18n 129 | i18n: $(I18Nmo) $(I18Npot) 130 | 131 | install-i18n: $(I18Nmsgs) 132 | 133 | ### Targets: 134 | 135 | $(SOFILE): $(OBJS) 136 | @echo LD $@ 137 | $(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@ 138 | $(Q)$(STRIP) $@ 139 | 140 | install-lib: $(SOFILE) 141 | @echo IN $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) 142 | $(Q)install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) 143 | 144 | install-conf: 145 | @mkdir -p $(DESTDIR)$(CFGDIR)/plugins/$(PLUGIN) 146 | 147 | install: install-lib install-i18n install-conf 148 | 149 | dist: $(I18Npo) clean 150 | @-rm -rf $(TMPDIR)/$(ARCHIVE) 151 | @mkdir $(TMPDIR)/$(ARCHIVE) 152 | @cp -a * $(TMPDIR)/$(ARCHIVE) 153 | @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) 154 | @-rm -rf $(TMPDIR)/$(ARCHIVE) 155 | @echo Distribution package created as $(PACKAGE).tgz 156 | 157 | clean: 158 | @-rm -f $(PODIR)/*.mo $(PODIR)/*.pot 159 | @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ 160 | 161 | .PHONY: cppcheck 162 | cppcheck: 163 | $(Q)cppcheck --language=c++ --enable=all -v -f $(OBJS:%.o=%.c) 164 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is an SAT>IP plugin for the Video Disk Recorder (VDR). 2 | 3 | Written by: Rolf Ahrenberg 4 | < R o l f . A h r e n b e r g @ s c i . f i > 5 | 6 | Project's homepage: https://github.com/rofafor/vdr-plugin-satip 7 | 8 | Latest version available at: https://github.com/rofafor/vdr-plugin-satip/releases 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License version 2 as 12 | published by the Free Software Foundation. 13 | See the file COPYING for more information. 14 | 15 | Requirements: 16 | 17 | - Libcurl >= 7.36.0 - the multiprotocol file transfer library with RTSP support 18 | http://curl.haxx.se/libcurl/ 19 | 20 | - PugiXML - Light-weight, simple and fast XML parser for C++ 21 | http://pugixml.org/ 22 | or 23 | TinyXML - a simple, small, C++ XML parser 24 | http://www.grinninglizard.com/tinyxml/ 25 | 26 | - Glibc >= 2.12 - the GNU C library (recvmmsg) 27 | http://www.gnu.org/software/libc/ 28 | 29 | Description: 30 | 31 | This plugin integrates SAT>IP network devices seamlessly into VDR. 32 | You can use any SAT>IP channel like any other normal DVB channel for 33 | live viewing, recording, etc. The plugin also features full section 34 | filtering capabilities which allow for example EIT information to be 35 | extracted from the incoming stream. 36 | 37 | Installation: 38 | 39 | tar -xzf /put/your/path/here/vdr-satip-X.Y.Z.tgz 40 | make -C satip-X.Y.Z install 41 | 42 | Configuration: 43 | 44 | The plugin accepts a "--devices" (-d) command-line parameter defaulting 45 | to two. This parameter defines how many simultaneous transponders can 46 | be received, if there are available SAT>IP tuners. 47 | 48 | The plugin accepts also a "--server" (-s) command-line parameter, that 49 | can be used to manually configure static SAT>IP servers if autodetection 50 | via UPnP somehow can't be used. Multiple service entries can be given 51 | separated by a semicolon: 52 | 53 | [@][:]|[:]|[:];... 54 | 55 | - srcaddress (Optional) Source address can be used to define used 56 | networking interface on a host, e.g. 127.0.0.1. 57 | - ipaddress IP address of SAT>IP server, e.g. 127.0.0.1. 58 | - port (Optional) IP port number of SAT>IP server, e.g 443. 59 | - model Model defines DVB modulation system (DVBS2, 60 | DVBT2, DVBT, DVBC) and number of available 61 | frontends separated by a hyphen, e.g. DVBT2-4. 62 | - filter (Optional) Filter can be used to limit satellite frontends 63 | to certain satellite position, e.g. S19.2E. 64 | - description Friendly name of SAT>IP server. This is used 65 | for autodetection of quirks. 66 | - quirk (Optional) Quirks are non-standard compliant features and 67 | bug fixes of SAT>IP server defined by a 68 | hexadecimal number. Multiple quirks can be 69 | defined by combining values by addition: 70 | 71 | 0x01: Fix session id bug 72 | 0x02: Fix play parameter (addpids/delpids) bug 73 | 0x04: Fix frontend locking bug 74 | 0x08: Support for RTP over TCP 75 | 0x10: Support the X_PMT protocol extension 76 | 0x20: Support the CI TNR protocol extension 77 | 0x40: Fix auto-detection of pilot tones bug 78 | 0x80: Fix re-tuning bug by teardowning a session 79 | 80 | Examples: 81 | 82 | vdr -P 'satip -s 192.168.0.1|DVBS2-2,DVBT2-2|OctopusNet' 83 | vdr -P 'satip -s 192.168.0.1|DVBS2-4|OctopusNet;192.168.0.2|DVBT2-4|minisatip:0x18' 84 | vdr -P 'satip -s 192.168.0.1:554|DVBS2-2:S19.2E|OctopusNet;192.168.0.2:8554|DVBS2-4:S19.2E,S1W|minisatip' 85 | 86 | The plugin accepts a "--portrange" (-p) command-line parameter, that can 87 | be used to manually specify the RTP & RTCP port range and therefore 88 | enables using the plugin through a NAT (e.g. Docker bridged network). 89 | A minimum of 2 ports per device is required. 90 | 91 | SAT>IP satellite positions (aka. signal sources) shall be defined via 92 | sources.conf. If the source description begins with a number, it's used 93 | as SAT>IP signal source selection parameter. A special number zero can 94 | be used to disable the source. Otherwise, the default parameter is one: 95 | 96 | S19.2E Astra 1KR/1L/1M/2C 97 | => Signal source = 1 98 | 99 | S19.2E 2 100 | => Signal source = 2 101 | 102 | S19.2E 3 Astra 1KR/1L/1M/2C 103 | => Signal source = 3 104 | 105 | S19.2E 0 Astra 1KR/1L/1M/2C 106 | => Source is disabled 107 | 108 | A channel can be assigned into a specific SAT>IP frontend by giving the 109 | identifier number in RID field of a channels.conf entry: 110 | FE = RID % 100 111 | Valid range: 1 ... 99 112 | 113 | Setup menu: 114 | 115 | - Operating mode = off If you want exclude all SAT>IP devices 116 | low from VDR's device handling, set this 117 | normal option to "off". Otherwise, if you want 118 | high to keep SAT>IP at a low priority when 119 | selecting available devices, set this 120 | option to "low". Similarly, the "high" 121 | value prefers the SAT>IP over the local 122 | DVB cards when selecting available devices. 123 | - Use CI extension = no If you want to use the CI extension found 124 | in some SAT>IP hardware (e.g. Digital 125 | Devices OctopusNet), set this option to 126 | "yes". 127 | - CICAM # = If you want to assign a CA system into 128 | a specific CI slot, set this option to 129 | a named one. Use "---" for autoselection. 130 | - Enable EPG scanning = yes If you want exclude all SAT>IP devices 131 | from VDR's EIT background scanning, set 132 | this option to "no". 133 | - Disabled sources = none If your SAT>IP servers don't have certain 134 | satellite positions available you can 135 | disable them via this option. 136 | - Disabled filters = none Certain section filters might cause some 137 | unwanted behaviour to VDR such as time 138 | being falsely synchronized etc. This option 139 | allows creation of blacklists of ill-behaving 140 | filters. If this option is set to a non-zero 141 | value, the menu page will contain that many 142 | "Disable filter" options which allow you 143 | to disable the individual section filters. 144 | Valid range: "none" = 0 ... 7 145 | - Transport mode = unicast If you want to use the non-standard 146 | multicast RTP-over-TCP transport mode, set this option 147 | rtp-o-tcp accordingly. Otherwise, the transport 148 | mode will be RTP-over-UDP via unicast or 149 | multicast. 150 | - Enable frontend reuse = yes Certain devices might have artifacts if 151 | multiple channels are assigned to the same 152 | frontend. If you want to avoid such a 153 | frontend assignment, set this option to "no". 154 | - [Red:Scan] Forces network scanning of SAT>IP hardware. 155 | - [Yellow:Devices] Opens SAT>IP device status menu. 156 | - [Blue:Info] Opens SAT>IP information/statistics menu. 157 | - [Ok] Opens information menu of selected SAT>IP 158 | device. 159 | 160 | Information menu: 161 | 162 | - [Red:General] Opens the general information page. 163 | - [Green:Pids] Opens the pid statistics page. 164 | - [Yellow:Filters] Opens the section filter statistics page. 165 | - [Blue:Bits/bytes] Toggles between bits and bytes mode. 166 | 167 | Notes: 168 | 169 | - If you are having problems receiving DVB-S2 channels, make sure your 170 | channels.conf entry contains correct pilot tone setting. 171 | 172 | - The stream id "-1" states about unsuccessful tuning. This might be a 173 | result of invalid channel parameters or lack of free SAT>IP tuners. 174 | 175 | - If the plugin doesn't detect your SAT>IP network device, make sure 176 | your setup doesn't have firewalled the UDP port 1900. 177 | 178 | - Stream decryption requires a separate CAM plugin that works without 179 | direct access to any DVB card devices. Also the integrated CAM slots 180 | in Octopus Net devices are supported. 181 | 182 | - Tracing can be set on/off dynamically via command-line switch or 183 | SVDRP command. 184 | 185 | - OctopusNet firmware 1.0.40 or greater recommended. 186 | 187 | - Inverto OEM firmware 1.17.0.120 or greater recommended. 188 | The firmware 1.16.0.120 can be downloaded and installed 189 | from their webpage: http://www.inverto.tv/support/ 190 | An update to a newer firmware should be offered afterwards. 191 | 192 | - FRITZ!OS 7.00 or greater recommended for FRITZ!Box Cable devices. 193 | Older firmware versions require both PlayPids and ForceLock quirks. 194 | 195 | - If you are experiencing glitches in the video stream, one possible 196 | reason can be buffer overflows in RTP receive sockets. You can verify 197 | this by checking "receive buffer errors" counter by running "netstat -s" 198 | command. If the counter increases every time a video glitch happens, 199 | you should try to tweak the RTP receive buffer size with the "--rcvbuf" 200 | (-r) plugin parameter. 201 | A good starting point for the buffer size is to double the operating 202 | system default value until errors disappear or the maximum value is 203 | reached. You can check these values in Linux by checking the kernel 204 | parameters: 205 | $ cat /proc/sys/net/core/rmem_default 206 | $ cat /proc/sys/net/core/rmem_max 207 | 208 | Acknowledgements: 209 | 210 | - Big thanks to Digital Devices GmbH for providing the Octopus Net 211 | hardware for development! 212 | -------------------------------------------------------------------------------- /common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * common.c: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | #include "common.h" 11 | 12 | uint16_t ts_pid(const uint8_t *bufP) 13 | { 14 | return (uint16_t)(((bufP[1] & 0x1f) << 8) + bufP[2]); 15 | } 16 | 17 | uint8_t payload(const uint8_t *bufP) 18 | { 19 | if (!(bufP[3] & 0x10)) // no payload? 20 | return 0; 21 | 22 | if (bufP[3] & 0x20) { // adaptation field? 23 | if (bufP[4] > 183) // corrupted data? 24 | return 0; 25 | else 26 | return (uint8_t)((184 - 1) - bufP[4]); 27 | } 28 | 29 | return 184; 30 | } 31 | 32 | const char *id_pid(const u_short pidP) 33 | { 34 | for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) { 35 | if (pidP == section_filter_table[i].pid) 36 | return section_filter_table[i].tag; 37 | } 38 | return "---"; 39 | } 40 | 41 | char *StripTags(char *strP) 42 | { 43 | if (strP) { 44 | char *c = strP, *r = strP, t = 0; 45 | while (*strP) { 46 | if (*strP == '<') 47 | ++t; 48 | else if (*strP == '>') 49 | --t; 50 | else if (t < 1) 51 | *(c++) = *strP; 52 | ++strP; 53 | } 54 | *c = 0; 55 | return r; 56 | } 57 | return NULL; 58 | } 59 | 60 | char *SkipZeroes(const char *strP) 61 | { 62 | if ((uchar)*strP != '0') 63 | return (char *)strP; 64 | while (*strP && (uchar)*strP == '0') 65 | strP++; 66 | return (char *)strP; 67 | } 68 | 69 | cString ChangeCase(const cString &strP, bool upperP) 70 | { 71 | cString res(strP); 72 | char *p = (char *)*res; 73 | while (p && *p) { 74 | *p = upperP ? toupper(*p) : tolower(*p); 75 | ++p; 76 | } 77 | return res; 78 | } 79 | 80 | const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE] = 81 | { 82 | // description tag pid tid mask 83 | {trNOOP("PAT (0x00)"), "PAT", 0x00, 0x00, 0xFF}, 84 | {trNOOP("NIT (0x40)"), "NIT", 0x10, 0x40, 0xFF}, 85 | {trNOOP("SDT (0x42)"), "SDT", 0x11, 0x42, 0xFF}, 86 | {trNOOP("EIT (0x4E/0x4F/0x5X/0x6X)"), "EIT", 0x12, 0x40, 0xC0}, 87 | {trNOOP("TDT (0x70)"), "TDT", 0x14, 0x70, 0xFF}, 88 | }; 89 | 90 | const ca_systems_table_type ca_systems_table[CA_SYSTEMS_TABLE_SIZE] = 91 | { 92 | // http://www.dvb.org/index.php?id=174 93 | // http://en.wikipedia.org/wiki/Conditional_access_system 94 | // start end description 95 | {0x0000, 0x0000, "---" }, // 0 96 | {0x0100, 0x01FF, "SECA Mediaguard (100..1FF)"}, // 1 97 | {0x0464, 0x0464, "EuroDec (464)" }, // 2 98 | {0x0500, 0x05FF, "Viaccess (500..5FF)" }, // 3 99 | {0x0600, 0x06FF, "Irdeto (600..6FF)" }, // 4 100 | {0x0700, 0x07FF, "DigiCipher 2 (700..7FF)" }, // 5 101 | {0x0900, 0x09FF, "NDS Videoguard (900..9FF)" }, // 6 102 | {0x0B00, 0x0BFF, "Conax (B00..BFF)" }, // 7 103 | {0x0D00, 0x0DFF, "CryptoWorks (D00..DFF)" }, // 8 104 | {0x0E00, 0x0EFF, "PowerVu (E00..EFF)" }, // 9 105 | {0x1000, 0x10FF, "RAS (1000..10FF)" }, // 10 106 | {0x1200, 0x12FF, "NagraVision (1200..12FF)" }, // 11 107 | {0x1700, 0x17FF, "VCAS (1700..17FF)" }, // 12 108 | {0x1800, 0x18FF, "NagraVision (1800..18FF)" }, // 13 109 | {0x22F0, 0x22F0, "Codicrypt (22F0)" }, // 14 110 | {0x2600, 0x2600, "BISS (2600)" }, // 15 111 | {0x2719, 0x2719, "VanyaCas (2719)" }, // 16 112 | {0x4347, 0x4347, "CryptOn (4347)" }, // 17 113 | {0x4800, 0x4800, "Accessgate (4800)" }, // 18 114 | {0x4900, 0x4900, "China Crypt (4900)" }, // 19 115 | {0x4A02, 0x4A02, "Tongfang (4A02)" }, // 20 116 | {0x4A10, 0x4A10, "EasyCas (4A10)" }, // 21 117 | {0x4A20, 0x4A20, "AlphaCrypt (4A20)" }, // 22 118 | {0x4A60, 0x4A60, "SkyCrypt (4A60)" }, // 23 119 | {0x4A61, 0x4A61, "Neotioncrypt (4A61)" }, // 24 120 | {0x4A62, 0x4A62, "SkyCrypt (4A62)" }, // 25 121 | {0x4A63, 0x4A63, "Neotion SHL (4A63)" }, // 26 122 | {0x4A64, 0x4A6F, "SkyCrypt (4A64)" }, // 27 123 | {0x4A70, 0x4A70, "DreamCrypt (4A70)" }, // 28 124 | {0x4A80, 0x4A80, "ThalesCrypt (4A80)" }, // 29 125 | {0x4AA1, 0x4AA1, "KeyFly (4AA1)" }, // 30 126 | {0x4ABF, 0x4ABF, "CTI-CAS (4ABF)" }, // 31 127 | {0x4AC1, 0x4AC1, "Latens (4AC1)" }, // 32 128 | {0x4AD0, 0x4AD1, "X-Crypt (4AD0)" }, // 33 129 | {0x4AD4, 0x4AD4, "OmniCrypt (4AD4)" }, // 34 130 | {0x4AE0, 0x4AE1, "Z-Crypt (4AE0)" }, // 35 131 | {0x4AE4, 0x4AE4, "CoreCrypt (4AE4)" }, // 36 132 | {0x4AE5, 0x4AE5, "PRO-Crypt (4AE5)" }, // 37 133 | {0x4AEA, 0x4AEA, "Cryptoguard (4AEA)" }, // 38 134 | {0x4AEB, 0x4AEB, "Abel Quintic (4AEB)" }, // 39 135 | {0x4AF0, 0x4AF0, "ABV (4AF0)" }, // 40 136 | {0x5500, 0x5500, "Z-Crypt (5500)" }, // 41 137 | {0x5501, 0x5501, "Griffin (5501)" }, // 42 138 | {0x5581, 0x5581, "Bulcrypt (5581)" }, // 43 139 | {0x7BE1, 0x7BE1, "DRE-Crypt (7BE1)" }, // 44 140 | {0xA101, 0xA101, "RosCrypt-M (A101)" }, // 45 141 | {0xEAD0, 0xEAD0, "VanyaCas (EAD0)" }, // 46 142 | }; 143 | 144 | bool checkCASystem(unsigned int cicamP, int caidP) 145 | { 146 | // always skip the first row 147 | if ((cicamP > 0) && (cicamP < ELEMENTS(ca_systems_table))) 148 | return ((caidP >= ca_systems_table[cicamP].start) && (caidP <= ca_systems_table[cicamP].end)); 149 | return false; 150 | } 151 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * common.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_COMMON_H 9 | #define __SATIP_COMMON_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define SATIP_DEFAULT_RTSP_PORT 554 17 | 18 | #define SATIP_MAX_DEVICES MAXDEVICES 19 | 20 | #define SATIP_BUFFER_SIZE KILOBYTE(2048) 21 | 22 | #define SATIP_DEVICE_INFO_ALL 0 23 | #define SATIP_DEVICE_INFO_GENERAL 1 24 | #define SATIP_DEVICE_INFO_PIDS 2 25 | #define SATIP_DEVICE_INFO_FILTERS 3 26 | #define SATIP_DEVICE_INFO_PROTOCOL 4 27 | #define SATIP_DEVICE_INFO_BITRATE 5 28 | 29 | #define SATIP_STATS_ACTIVE_PIDS_COUNT 10 30 | #define SATIP_STATS_ACTIVE_FILTERS_COUNT 10 31 | 32 | #define MAX_DISABLED_SOURCES_COUNT 25 33 | #define SECTION_FILTER_TABLE_SIZE 5 34 | 35 | #define MAX_CICAM_COUNT 2 36 | #define CA_SYSTEMS_TABLE_SIZE 47 37 | 38 | #define SATIP_CURL_EASY_GETINFO(X, Y, Z) \ 39 | if ((res = curl_easy_getinfo((X), (Y), (Z))) != CURLE_OK) { \ 40 | esyslog("curl_easy_getinfo(%s) [%s,%d] failed: %s (%d)", #Y, __FILE__, __LINE__, curl_easy_strerror(res), res); \ 41 | } 42 | 43 | #define SATIP_CURL_EASY_SETOPT(X, Y, Z) \ 44 | if ((res = curl_easy_setopt((X), (Y), (Z))) != CURLE_OK) { \ 45 | esyslog("curl_easy_setopt(%s, %s) [%s,%d] failed: %s (%d)", #Y, #Z, __FILE__, __LINE__, curl_easy_strerror(res), res); \ 46 | } 47 | 48 | #define SATIP_CURL_EASY_PERFORM(X) \ 49 | if ((res = curl_easy_perform((X))) != CURLE_OK) { \ 50 | esyslog("curl_easy_perform() [%s,%d] failed: %s (%d)", __FILE__, __LINE__, curl_easy_strerror(res), res); \ 51 | } 52 | 53 | #define ERROR_IF_FUNC(exp, errstr, func, ret) \ 54 | do { \ 55 | if (exp) { \ 56 | char tmp[64]; \ 57 | esyslog("[%s,%d]: " errstr ": %s", __FILE__, __LINE__, \ 58 | strerror_r(errno, tmp, sizeof(tmp))); \ 59 | func; \ 60 | ret; \ 61 | } \ 62 | } while (0) 63 | 64 | 65 | #define ERROR_IF_RET(exp, errstr, ret) ERROR_IF_FUNC(exp, errstr, ,ret); 66 | 67 | #define ERROR_IF(exp, errstr) ERROR_IF_FUNC(exp, errstr, , ); 68 | 69 | #define DELETE_POINTER(ptr) \ 70 | do { \ 71 | if (ptr) { \ 72 | typeof(*ptr) *tmp = ptr; \ 73 | ptr = NULL; \ 74 | delete(tmp); \ 75 | } \ 76 | } while (0) 77 | 78 | #define FREE_POINTER(ptr) \ 79 | do { \ 80 | if (ptr) { \ 81 | typeof(*ptr) *tmp = ptr; \ 82 | ptr = NULL; \ 83 | free(tmp); \ 84 | } \ 85 | } while (0) 86 | 87 | #define ELEMENTS(x) (sizeof(x) / sizeof(x[0])) 88 | 89 | class cSatipMemoryBuffer { 90 | private: 91 | enum { 92 | eMaxDataSize = MEGABYTE(2) 93 | }; 94 | char *dataM; 95 | size_t sizeM; 96 | void *AllocBuffer(void *ptrP, size_t sizeP) 97 | { 98 | // There might be a realloc() out there that doesn't like reallocing NULL pointers, so we take care of it here 99 | if (ptrP) 100 | return realloc(ptrP, sizeP); 101 | else 102 | return malloc(sizeP); 103 | } 104 | // to prevent copy constructor and assignment 105 | cSatipMemoryBuffer(const cSatipMemoryBuffer&); 106 | cSatipMemoryBuffer& operator=(const cSatipMemoryBuffer&); 107 | public: 108 | cSatipMemoryBuffer() : dataM(NULL), sizeM(0) {} 109 | ~cSatipMemoryBuffer() { Reset(); } 110 | size_t Add(char *dataP, size_t sizeP) 111 | { 112 | if (sizeP > 0) { 113 | size_t len = sizeM + sizeP + 1; 114 | if (len < eMaxDataSize) { 115 | dataM = (char *)AllocBuffer(dataM, len); 116 | if (dataM) { 117 | memcpy(&(dataM[sizeM]), dataP, sizeP); 118 | sizeM += sizeP; 119 | dataM[sizeM] = 0; 120 | return sizeP; 121 | } 122 | else 123 | esyslog("[%s,%d]: Failed to allocate memory", __FILE__, __LINE__); 124 | } 125 | else 126 | esyslog("[%s,%d]: Buffer overflow", __FILE__, __LINE__); 127 | } 128 | return 0; 129 | }; 130 | char *Data(void) { return dataM; } 131 | size_t Size(void) { return sizeM; } 132 | void Reset(void) { FREE_POINTER(dataM); sizeM = 0; }; 133 | }; 134 | 135 | uint16_t ts_pid(const uint8_t *bufP); 136 | uint8_t payload(const uint8_t *bufP); 137 | const char *id_pid(const u_short pidP); 138 | char *StripTags(char *strP); 139 | char *SkipZeroes(const char *strP); 140 | cString ChangeCase(const cString &strP, bool upperP); 141 | 142 | struct section_filter_table_type { 143 | const char *description; 144 | const char *tag; 145 | u_short pid; 146 | u_char tid; 147 | u_char mask; 148 | }; 149 | 150 | extern const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE]; 151 | 152 | struct ca_systems_table_type { 153 | int start; 154 | int end; 155 | const char *description; 156 | }; 157 | 158 | extern const ca_systems_table_type ca_systems_table[CA_SYSTEMS_TABLE_SIZE]; 159 | extern bool checkCASystem(unsigned int cicamP, int caidP); 160 | 161 | extern const char VERSION[]; 162 | 163 | #endif // __SATIP_COMMON_H 164 | 165 | -------------------------------------------------------------------------------- /config.c: -------------------------------------------------------------------------------- 1 | /* 2 | * config.c: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #include "discover.h" 9 | #include "log.h" 10 | #include "config.h" 11 | 12 | cSatipConfig SatipConfig; 13 | 14 | cSatipConfig::cSatipConfig(void) 15 | : operatingModeM(eOperatingModeLow), 16 | traceModeM(eTraceModeNormal), 17 | ciExtensionM(0), 18 | frontendReuseM(1), 19 | eitScanM(1), 20 | useBytesM(1), 21 | portRangeStartM(0), 22 | portRangeStopM(0), 23 | transportModeM(eTransportModeUnicast), 24 | detachedModeM(false), 25 | disableServerQuirksM(false), 26 | useSingleModelServersM(false), 27 | rtpRcvBufSizeM(0) 28 | { 29 | for (unsigned int i = 0; i < ELEMENTS(cicamsM); ++i) 30 | cicamsM[i] = 0; 31 | for (unsigned int i = 0; i < ELEMENTS(disabledSourcesM); ++i) 32 | disabledSourcesM[i] = cSource::stNone; 33 | for (unsigned int i = 0; i < ELEMENTS(disabledFiltersM); ++i) 34 | disabledFiltersM[i] = -1; 35 | } 36 | 37 | int cSatipConfig::GetCICAM(unsigned int indexP) const 38 | { 39 | return (indexP < ELEMENTS(cicamsM)) ? cicamsM[indexP] : -1; 40 | } 41 | 42 | void cSatipConfig::SetCICAM(unsigned int indexP, int cicamP) 43 | { 44 | if (indexP < ELEMENTS(cicamsM)) 45 | cicamsM[indexP] = cicamP; 46 | } 47 | 48 | unsigned int cSatipConfig::GetDisabledSourcesCount(void) const 49 | { 50 | unsigned int n = 0; 51 | while ((n < ELEMENTS(disabledSourcesM) && (disabledSourcesM[n] != cSource::stNone))) 52 | n++; 53 | return n; 54 | } 55 | 56 | int cSatipConfig::GetDisabledSources(unsigned int indexP) const 57 | { 58 | return (indexP < ELEMENTS(disabledSourcesM)) ? disabledSourcesM[indexP] : cSource::stNone; 59 | } 60 | 61 | void cSatipConfig::SetDisabledSources(unsigned int indexP, int sourceP) 62 | { 63 | if (indexP < ELEMENTS(disabledSourcesM)) 64 | disabledSourcesM[indexP] = sourceP; 65 | } 66 | 67 | unsigned int cSatipConfig::GetDisabledFiltersCount(void) const 68 | { 69 | unsigned int n = 0; 70 | while ((n < ELEMENTS(disabledFiltersM) && (disabledFiltersM[n] != -1))) 71 | n++; 72 | return n; 73 | } 74 | 75 | int cSatipConfig::GetDisabledFilters(unsigned int indexP) const 76 | { 77 | return (indexP < ELEMENTS(disabledFiltersM)) ? disabledFiltersM[indexP] : -1; 78 | } 79 | 80 | void cSatipConfig::SetDisabledFilters(unsigned int indexP, int numberP) 81 | { 82 | if (indexP < ELEMENTS(disabledFiltersM)) 83 | disabledFiltersM[indexP] = numberP; 84 | } 85 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * config.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_CONFIG_H 9 | #define __SATIP_CONFIG_H 10 | 11 | #include 12 | #include "common.h" 13 | 14 | class cSatipConfig 15 | { 16 | private: 17 | unsigned int operatingModeM; 18 | unsigned int traceModeM; 19 | unsigned int ciExtensionM; 20 | unsigned int frontendReuseM; 21 | unsigned int eitScanM; 22 | unsigned int useBytesM; 23 | unsigned int portRangeStartM; 24 | unsigned int portRangeStopM; 25 | unsigned int transportModeM; 26 | bool detachedModeM; 27 | bool disableServerQuirksM; 28 | bool useSingleModelServersM; 29 | int cicamsM[MAX_CICAM_COUNT]; 30 | int disabledSourcesM[MAX_DISABLED_SOURCES_COUNT]; 31 | int disabledFiltersM[SECTION_FILTER_TABLE_SIZE]; 32 | size_t rtpRcvBufSizeM; 33 | 34 | public: 35 | enum eOperatingMode { 36 | eOperatingModeOff = 0, 37 | eOperatingModeLow, 38 | eOperatingModeNormal, 39 | eOperatingModeHigh, 40 | eOperatingModeCount 41 | }; 42 | enum eTransportMode { 43 | eTransportModeUnicast = 0, 44 | eTransportModeMulticast, 45 | eTransportModeRtpOverTcp, 46 | eTransportModeCount 47 | }; 48 | enum eTraceMode { 49 | eTraceModeNormal = 0x0000, 50 | eTraceModeDebug1 = 0x0001, 51 | eTraceModeDebug2 = 0x0002, 52 | eTraceModeDebug3 = 0x0004, 53 | eTraceModeDebug4 = 0x0008, 54 | eTraceModeDebug5 = 0x0010, 55 | eTraceModeDebug6 = 0x0020, 56 | eTraceModeDebug7 = 0x0040, 57 | eTraceModeDebug8 = 0x0080, 58 | eTraceModeDebug9 = 0x0100, 59 | eTraceModeDebug10 = 0x0200, 60 | eTraceModeDebug11 = 0x0400, 61 | eTraceModeDebug12 = 0x0800, 62 | eTraceModeDebug13 = 0x1000, 63 | eTraceModeDebug14 = 0x2000, 64 | eTraceModeDebug15 = 0x4000, 65 | eTraceModeDebug16 = 0x8000, 66 | eTraceModeMask = 0xFFFF 67 | }; 68 | cSatipConfig(); 69 | unsigned int GetOperatingMode(void) const { return operatingModeM; } 70 | bool IsOperatingModeOff(void) const { return (operatingModeM == eOperatingModeOff); } 71 | bool IsOperatingModeLow(void) const { return (operatingModeM == eOperatingModeLow); } 72 | bool IsOperatingModeNormal(void) const { return (operatingModeM == eOperatingModeNormal); } 73 | bool IsOperatingModeHigh(void) const { return (operatingModeM == eOperatingModeHigh); } 74 | void ToggleOperatingMode(void) { operatingModeM = (operatingModeM + 1) % eOperatingModeCount; } 75 | unsigned int GetTraceMode(void) const { return traceModeM; } 76 | bool IsTraceMode(eTraceMode modeP) const { return (traceModeM & modeP); } 77 | unsigned int GetCIExtension(void) const { return ciExtensionM; } 78 | unsigned int GetFrontendReuse(void) const { return frontendReuseM; } 79 | int GetCICAM(unsigned int indexP) const; 80 | unsigned int GetEITScan(void) const { return eitScanM; } 81 | unsigned int GetUseBytes(void) const { return useBytesM; } 82 | unsigned int GetTransportMode(void) const { return transportModeM; } 83 | bool IsTransportModeUnicast(void) const { return (transportModeM == eTransportModeUnicast); } 84 | bool IsTransportModeRtpOverTcp(void) const { return (transportModeM == eTransportModeRtpOverTcp); } 85 | bool IsTransportModeMulticast(void) const { return (transportModeM == eTransportModeMulticast); } 86 | bool GetDetachedMode(void) const { return detachedModeM; } 87 | bool GetDisableServerQuirks(void) const { return disableServerQuirksM; } 88 | bool GetUseSingleModelServers(void) const { return useSingleModelServersM; } 89 | unsigned int GetDisabledSourcesCount(void) const; 90 | int GetDisabledSources(unsigned int indexP) const; 91 | unsigned int GetDisabledFiltersCount(void) const; 92 | int GetDisabledFilters(unsigned int indexP) const; 93 | unsigned int GetPortRangeStart(void) const { return portRangeStartM; } 94 | unsigned int GetPortRangeStop(void) const { return portRangeStopM; } 95 | size_t GetRtpRcvBufSize(void) const { return rtpRcvBufSizeM; } 96 | 97 | void SetOperatingMode(unsigned int operatingModeP) { operatingModeM = operatingModeP; } 98 | void SetTraceMode(unsigned int modeP) { traceModeM = (modeP & eTraceModeMask); } 99 | void SetCIExtension(unsigned int onOffP) { ciExtensionM = onOffP; } 100 | void SetFrontendReuse(unsigned int onOffP) { frontendReuseM = onOffP; } 101 | void SetCICAM(unsigned int indexP, int cicamP); 102 | void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; } 103 | void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; } 104 | void SetTransportMode(unsigned int transportModeP) { transportModeM = transportModeP; } 105 | void SetDetachedMode(bool onOffP) { detachedModeM = onOffP; } 106 | void SetDisableServerQuirks(bool onOffP) { disableServerQuirksM = onOffP; } 107 | void SetUseSingleModelServers(bool onOffP) { useSingleModelServersM = onOffP; } 108 | void SetDisabledSources(unsigned int indexP, int sourceP); 109 | void SetDisabledFilters(unsigned int indexP, int numberP); 110 | void SetPortRangeStart(unsigned int rangeStartP) { portRangeStartM = rangeStartP; } 111 | void SetPortRangeStop(unsigned int rangeStopP) { portRangeStopM = rangeStopP; } 112 | void SetRtpRcvBufSize(size_t sizeP) { rtpRcvBufSizeM = sizeP; } 113 | }; 114 | 115 | extern cSatipConfig SatipConfig; 116 | 117 | #endif // __SATIP_CONFIG_H 118 | -------------------------------------------------------------------------------- /detectsatip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ Simple tool to detect SAT>IP devices as JSON. 3 | """ 4 | import json 5 | import socket 6 | import sys 7 | import xml.etree.ElementTree as ET 8 | import requests 9 | 10 | SSDP_BIND = "0.0.0.0" 11 | SSDP_ADDR = "239.255.255.250" 12 | SSDP_PORT = 1900 13 | SSDP_MX = 1 14 | SSDP_ST = "urn:ses-com:device:SatIPServer:1" 15 | SSDP_REQUEST = "\r\n".join( 16 | [ 17 | "M-SEARCH * HTTP/1.1", 18 | f"HOST: {SSDP_ADDR}:{SSDP_PORT}", 19 | 'MAN: "ssdp:discover"', 20 | f"MX: {SSDP_MX}", 21 | f"ST: {SSDP_ST}", 22 | "USER-AGENT: vdr-detectsatip", 23 | "\r\n", 24 | ] 25 | ) 26 | 27 | 28 | def parse_satip_xml(data): 29 | """Parse SAT>IP XML data. 30 | 31 | Args: 32 | data (str): XML input data.. 33 | 34 | Returns: 35 | dict: Parsed SAT>IP device name and frontend information. 36 | """ 37 | result = {"name": "", "frontends": {}} 38 | if data: 39 | root = ET.fromstring(data) 40 | name = root.find(".//*/{urn:schemas-upnp-org:device-1-0}friendlyName") 41 | result["name"] = name.text 42 | satipcap = root.find(".//*/{urn:ses-com:satip}X_SATIPCAP") 43 | if satipcap is None: 44 | # fallback for non-standard Panasonic 45 | satipcap = root.find(".//*/{urn-ses-com:satip}X_SATIPCAP") 46 | caps = {} 47 | for system in satipcap.text.split(","): 48 | cap = system.split("-") 49 | if cap: 50 | count = int(cap[1]) 51 | if cap[0] in caps: 52 | count = count + caps[cap[0]] 53 | caps[cap[0]] = count 54 | result["frontends"] = caps 55 | return result 56 | 57 | 58 | def detect_satip_devices(): 59 | """Detect available SAT>IP devices by sending a broadcast message. 60 | 61 | Returns: 62 | list: Found SAT>IP devices. 63 | """ 64 | urls = [] 65 | devices = [] 66 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 67 | sock.setblocking(0) 68 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) 69 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 70 | try: 71 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) 72 | except BaseException: 73 | pass 74 | sock.settimeout(1) 75 | sock.bind((SSDP_BIND, SSDP_PORT)) 76 | sock.sendto(SSDP_REQUEST.encode("utf-8"), (SSDP_ADDR, SSDP_PORT)) 77 | try: 78 | while 1: 79 | data = sock.recv(1024).decode("utf-8") 80 | if data: 81 | for row in data.split("\r\n"): 82 | if "LOCATION:" in row: 83 | url = row.replace("LOCATION:", "").strip() 84 | if url in urls: 85 | continue 86 | urls.append(url) 87 | info = requests.get(url, timeout=2) 88 | devices.append(parse_satip_xml(info.text)) 89 | else: 90 | break 91 | except BaseException: 92 | pass 93 | sock.close() 94 | return devices 95 | 96 | 97 | if __name__ == "__main__": 98 | json.dump(detect_satip_devices(), fp=sys.stdout, sort_keys=True, indent=2) 99 | -------------------------------------------------------------------------------- /device.h: -------------------------------------------------------------------------------- 1 | /* 2 | * device.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_DEVICE_H 9 | #define __SATIP_DEVICE_H 10 | 11 | #include 12 | #include "common.h" 13 | #include "deviceif.h" 14 | #include "tuner.h" 15 | #include "sectionfilter.h" 16 | #include "statistics.h" 17 | 18 | class cSatipDevice : public cDevice, public cSatipPidStatistics, public cSatipBufferStatistics, public cSatipDeviceIf { 19 | // static ones 20 | public: 21 | static cMutex mutexS; 22 | static bool Initialize(unsigned int DeviceCount); 23 | static void Shutdown(void); 24 | static unsigned int Count(void); 25 | static cSatipDevice *GetSatipDevice(int CardIndex); 26 | static cString GetSatipStatus(void); 27 | 28 | // private parts 29 | private: 30 | enum { 31 | eReadyTimeoutMs = 2000, // in milliseconds 32 | eTuningTimeoutMs = 1000 // in milliseconds 33 | }; 34 | unsigned int deviceIndexM; 35 | int bytesDeliveredM; 36 | bool isOpenDvrM; 37 | bool checkTsBufferM; 38 | cString deviceNameM; 39 | cChannel channelM; 40 | cRingBufferLinear *tsBufferM; 41 | cSatipTuner *pTunerM; 42 | cSatipSectionFilterHandler *pSectionFilterHandlerM; 43 | cTimeMs createdM; 44 | cCondVar tunedM; 45 | 46 | // constructor & destructor 47 | public: 48 | explicit cSatipDevice(unsigned int deviceIndexP); 49 | virtual ~cSatipDevice(); 50 | cString GetInformation(unsigned int pageP = SATIP_DEVICE_INFO_ALL); 51 | 52 | // copy and assignment constructors 53 | private: 54 | cSatipDevice(const cSatipDevice&); 55 | cSatipDevice& operator=(const cSatipDevice&); 56 | 57 | // for statistics and general information 58 | cString GetGeneralInformation(void); 59 | cString GetPidsInformation(void); 60 | cString GetFiltersInformation(void); 61 | 62 | // for channel info 63 | public: 64 | virtual bool Ready(void); 65 | virtual cString DeviceType(void) const; 66 | virtual cString DeviceName(void) const; 67 | virtual bool AvoidRecording(void) const; 68 | virtual bool SignalStats(int &Valid, double *Strength = NULL, double *Cnr = NULL, double *BerPre = NULL, double *BerPost = NULL, double *Per = NULL, int *Status = NULL) const; 69 | virtual int SignalStrength(void) const; 70 | virtual int SignalQuality(void) const; 71 | 72 | // for channel selection 73 | public: 74 | virtual bool ProvidesSource(int sourceP) const; 75 | virtual bool ProvidesTransponder(const cChannel *channelP) const; 76 | virtual bool ProvidesChannel(const cChannel *channelP, int priorityP = -1, bool *needsDetachReceiversP = NULL) const; 77 | virtual bool ProvidesEIT(void) const; 78 | virtual int NumProvidedSystems(void) const; 79 | virtual const cChannel *GetCurrentlyTunedTransponder(void) const; 80 | virtual bool IsTunedToTransponder(const cChannel *channelP) const; 81 | virtual bool MaySwitchTransponder(const cChannel *channelP) const; 82 | 83 | protected: 84 | virtual bool SetChannelDevice(const cChannel *channelP, bool liveViewP); 85 | 86 | // for recording 87 | private: 88 | uchar *GetData(int *availableP = NULL, bool checkTsBuffer = false); 89 | void SkipData(int countP); 90 | 91 | protected: 92 | virtual bool SetPid(cPidHandle *handleP, int typeP, bool onP); 93 | virtual bool OpenDvr(void); 94 | virtual void CloseDvr(void); 95 | virtual bool GetTSPacket(uchar *&dataP); 96 | 97 | // for section filtering 98 | public: 99 | virtual int OpenFilter(u_short pidP, u_char tidP, u_char maskP); 100 | virtual void CloseFilter(int handleP); 101 | 102 | // for transponder lock 103 | public: 104 | virtual bool HasLock(int timeoutMsP = 0) const; 105 | 106 | // for common interface 107 | public: 108 | virtual bool HasInternalCam(void); 109 | 110 | // for internal device interface 111 | public: 112 | virtual void WriteData(u_char *bufferP, int lengthP); 113 | virtual void SetChannelTuned(void); 114 | virtual int GetId(void); 115 | virtual int GetPmtPid(void); 116 | virtual int GetCISlot(void); 117 | virtual cString GetTnrParameterString(void); 118 | virtual bool IsIdle(void); 119 | }; 120 | 121 | #endif // __SATIP_DEVICE_H 122 | -------------------------------------------------------------------------------- /deviceif.h: -------------------------------------------------------------------------------- 1 | /* 2 | * deviceif.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_DEVICEIF_H 9 | #define __SATIP_DEVICEIF_H 10 | 11 | class cSatipDeviceIf { 12 | public: 13 | cSatipDeviceIf() {} 14 | virtual ~cSatipDeviceIf() {} 15 | virtual void WriteData(u_char *bufferP, int lengthP) = 0; 16 | virtual void SetChannelTuned(void) = 0; 17 | virtual int GetId(void) = 0; 18 | virtual int GetPmtPid(void) = 0; 19 | virtual int GetCISlot(void) = 0; 20 | virtual cString GetTnrParameterString(void) = 0; 21 | virtual bool IsIdle(void) = 0; 22 | 23 | private: 24 | explicit cSatipDeviceIf(const cSatipDeviceIf&); 25 | cSatipDeviceIf& operator=(const cSatipDeviceIf&); 26 | }; 27 | 28 | #endif // __SATIP_DEVICEIF_H 29 | -------------------------------------------------------------------------------- /discover.c: -------------------------------------------------------------------------------- 1 | /* 2 | * discover.c: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #include 9 | #ifdef USE_TINYXML 10 | #include 11 | #else 12 | #include 13 | #endif 14 | #include "common.h" 15 | #include "config.h" 16 | #include "log.h" 17 | #include "socket.h" 18 | #include "discover.h" 19 | 20 | cSatipDiscover *cSatipDiscover::instanceS = NULL; 21 | 22 | cSatipDiscover *cSatipDiscover::GetInstance(void) 23 | { 24 | if (!instanceS) 25 | instanceS = new cSatipDiscover(); 26 | return instanceS; 27 | } 28 | 29 | bool cSatipDiscover::Initialize(cSatipDiscoverServers *serversP) 30 | { 31 | debug1("%s", __PRETTY_FUNCTION__); 32 | if (instanceS) { 33 | if (serversP) { 34 | for (cSatipDiscoverServer *s = serversP->First(); s; s = serversP->Next(s)) 35 | instanceS->AddServer(s->SrcAddress(), s->IpAddress(), s->IpPort(), s->Model(), s->Filters(), s->Description(), s->Quirk()); 36 | } 37 | else 38 | instanceS->Activate(); 39 | } 40 | return true; 41 | } 42 | 43 | void cSatipDiscover::Destroy(void) 44 | { 45 | debug1("%s", __PRETTY_FUNCTION__); 46 | if (instanceS) 47 | instanceS->Deactivate(); 48 | } 49 | 50 | size_t cSatipDiscover::HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP) 51 | { 52 | cSatipDiscover *obj = reinterpret_cast(dataP); 53 | size_t len = sizeP * nmembP; 54 | debug16("%s len=%zu", __PRETTY_FUNCTION__, len); 55 | 56 | if (obj && (len > 0)) 57 | obj->headerBufferM.Add(ptrP, len); 58 | 59 | return len; 60 | } 61 | 62 | size_t cSatipDiscover::DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP) 63 | { 64 | cSatipDiscover *obj = reinterpret_cast(dataP); 65 | size_t len = sizeP * nmembP; 66 | debug16("%s len=%zu", __PRETTY_FUNCTION__, len); 67 | 68 | if (obj && (len > 0)) 69 | obj->dataBufferM.Add(ptrP, len); 70 | 71 | return len; 72 | } 73 | 74 | int cSatipDiscover::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP) 75 | { 76 | cSatipDiscover *obj = reinterpret_cast(userPtrP); 77 | 78 | if (obj) { 79 | switch (typeP) { 80 | case CURLINFO_TEXT: 81 | debug2("%s HTTP INFO %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP); 82 | break; 83 | case CURLINFO_HEADER_IN: 84 | debug2("%s HTTP HEAD <<< %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP); 85 | break; 86 | case CURLINFO_HEADER_OUT: 87 | debug2("%s HTTP HEAD >>>\n%.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP); 88 | break; 89 | case CURLINFO_DATA_IN: 90 | debug2("%s HTTP DATA <<< %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP); 91 | break; 92 | case CURLINFO_DATA_OUT: 93 | debug2("%s HTTP DATA >>>\n%.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP); 94 | break; 95 | default: 96 | break; 97 | } 98 | } 99 | 100 | return 0; 101 | } 102 | 103 | cSatipDiscover::cSatipDiscover() 104 | : cThread("SATIP discover"), 105 | mutexM(), 106 | headerBufferM(), 107 | dataBufferM(), 108 | msearchM(*this), 109 | probeUrlListM(), 110 | handleM(curl_easy_init()), 111 | sleepM(), 112 | probeIntervalM(0), 113 | serversM() 114 | { 115 | debug1("%s", __PRETTY_FUNCTION__); 116 | } 117 | 118 | cSatipDiscover::~cSatipDiscover() 119 | { 120 | debug1("%s", __PRETTY_FUNCTION__); 121 | Deactivate(); 122 | cMutexLock MutexLock(&mutexM); 123 | // Free allocated memory 124 | if (handleM) 125 | curl_easy_cleanup(handleM); 126 | handleM = NULL; 127 | probeUrlListM.Clear(); 128 | } 129 | 130 | void cSatipDiscover::Activate(void) 131 | { 132 | // Start the thread 133 | Start(); 134 | } 135 | 136 | void cSatipDiscover::Deactivate(void) 137 | { 138 | debug1("%s", __PRETTY_FUNCTION__); 139 | cMutexLock MutexLock(&mutexM); 140 | sleepM.Signal(); 141 | if (Running()) 142 | Cancel(3); 143 | } 144 | 145 | void cSatipDiscover::Action(void) 146 | { 147 | debug1("%s Entering", __PRETTY_FUNCTION__); 148 | probeIntervalM.Set(eProbeIntervalMs); 149 | msearchM.Probe(); 150 | // Do the thread loop 151 | while (Running()) { 152 | cStringList tmp; 153 | 154 | if (probeIntervalM.TimedOut()) { 155 | probeIntervalM.Set(eProbeIntervalMs); 156 | msearchM.Probe(); 157 | mutexM.Lock(); 158 | serversM.Cleanup(eCleanupTimeoutMs); 159 | mutexM.Unlock(); 160 | } 161 | mutexM.Lock(); 162 | if (probeUrlListM.Size()) { 163 | for (int i = 0; i < probeUrlListM.Size(); ++i) 164 | tmp.Insert(strdup(probeUrlListM.At(i))); 165 | probeUrlListM.Clear(); 166 | } 167 | mutexM.Unlock(); 168 | if (tmp.Size()) { 169 | for (int i = 0; i < tmp.Size(); ++i) 170 | Fetch(tmp.At(i)); 171 | tmp.Clear(); 172 | } 173 | // to avoid busy loop and reduce cpu load 174 | sleepM.Wait(eSleepTimeoutMs); 175 | } 176 | debug1("%s Exiting", __PRETTY_FUNCTION__); 177 | } 178 | 179 | void cSatipDiscover::Fetch(const char *urlP) 180 | { 181 | debug1("%s (%s)", __PRETTY_FUNCTION__, urlP); 182 | if (handleM && !isempty(urlP)) { 183 | const char *addr = NULL; 184 | long rc = 0; 185 | CURLcode res = CURLE_OK; 186 | 187 | // Verbose output 188 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L); 189 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGFUNCTION, cSatipDiscover::DebugCallback); 190 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGDATA, this); 191 | 192 | // Set header and data callbacks 193 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipDiscover::HeaderCallback); 194 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this); 195 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::DataCallback); 196 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); 197 | 198 | // No progress meter and no signaling 199 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L); 200 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L); 201 | 202 | // Set timeouts 203 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs); 204 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs); 205 | 206 | // Set user-agent 207 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION)); 208 | 209 | // Set URL 210 | SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, urlP); 211 | 212 | // Fetch the data 213 | SATIP_CURL_EASY_PERFORM(handleM); 214 | SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc); 215 | SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_PRIMARY_IP, &addr); 216 | if (rc == 200) { 217 | ParseDeviceInfo(addr, ParseRtspPort()); 218 | headerBufferM.Reset(); 219 | dataBufferM.Reset(); 220 | } 221 | else 222 | error("Discovery detected invalid status code: %ld", rc); 223 | } 224 | } 225 | 226 | int cSatipDiscover::ParseRtspPort(void) 227 | { 228 | debug1("%s", __PRETTY_FUNCTION__); 229 | char *s, *p = headerBufferM.Data(); 230 | char *r = strtok_r(p, "\r\n", &s); 231 | int port = SATIP_DEFAULT_RTSP_PORT; 232 | 233 | while (r) { 234 | debug16("%s (%zu): %s", __PRETTY_FUNCTION__, headerBufferM.Size(), r); 235 | r = skipspace(r); 236 | if (strstr(r, "X-SATIP-RTSP-Port")) { 237 | int tmp = -1; 238 | if (sscanf(r, "X-SATIP-RTSP-Port:%11d", &tmp) == 1) { 239 | port = tmp; 240 | break; 241 | } 242 | } 243 | r = strtok_r(NULL, "\r\n", &s); 244 | } 245 | 246 | return port; 247 | } 248 | 249 | void cSatipDiscover::ParseDeviceInfo(const char *addrP, const int portP) 250 | { 251 | debug1("%s (%s, %d)", __PRETTY_FUNCTION__, addrP, portP); 252 | const char *desc = NULL, *model = NULL; 253 | #ifdef USE_TINYXML 254 | TiXmlDocument doc; 255 | doc.Parse(dataBufferM.Data()); 256 | TiXmlHandle docHandle(&doc); 257 | TiXmlElement *descElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("friendlyName").ToElement(); 258 | if (descElement) 259 | desc = descElement->GetText() ? descElement->GetText() : "MyBrokenHardware"; 260 | TiXmlElement *modelElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("satip:X_SATIPCAP").ToElement(); 261 | if (modelElement) 262 | model = modelElement->GetText() ? modelElement->GetText() : "DVBS2-1"; 263 | #else 264 | pugi::xml_document doc; 265 | if (doc.load_buffer(dataBufferM.Data(), dataBufferM.Size())) { 266 | pugi::xml_node descNode = doc.first_element_by_path("root/device/friendlyName"); 267 | if (descNode) 268 | desc = descNode.text().as_string("MyBrokenHardware"); 269 | pugi::xml_node modelNode = doc.first_element_by_path("root/device/satip:X_SATIPCAP"); 270 | if (modelNode) 271 | model = modelNode.text().as_string("DVBS2-1"); 272 | } 273 | #endif 274 | AddServer(NULL, addrP, portP, model, NULL, desc, cSatipServer::eSatipQuirkNone); 275 | } 276 | 277 | void cSatipDiscover::AddServer(const char *srcAddrP, const char *addrP, const int portP, const char *modelP, const char *filtersP, const char *descP, const int quirkP) 278 | { 279 | debug1("%s (%s, %s, %d, %s, %s, %s, %d)", __PRETTY_FUNCTION__, srcAddrP, addrP, portP, modelP, filtersP, descP, quirkP); 280 | cMutexLock MutexLock(&mutexM); 281 | if (SatipConfig.GetUseSingleModelServers() && modelP && !isempty(modelP)) { 282 | int n = 0; 283 | char *s, *p = strdup(modelP); 284 | char *r = strtok_r(p, ",", &s); 285 | while (r) { 286 | r = skipspace(r); 287 | cString desc = cString::sprintf("%s #%d", !isempty(descP) ? descP : "MyBrokenHardware", n++); 288 | cSatipServer *tmp = new cSatipServer(srcAddrP, addrP, portP, r, filtersP, desc, quirkP); 289 | if (!serversM.Update(tmp)) { 290 | info("Adding server '%s|%s|%s' Bind: %s Filters: %s CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), !isempty(tmp->SrcAddress()) ? tmp->SrcAddress() : "default", !isempty(tmp->Filters()) ? tmp->Filters() : "none", tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none"); 291 | serversM.Add(tmp); 292 | } 293 | else 294 | DELETENULL(tmp); 295 | r = strtok_r(NULL, ",", &s); 296 | } 297 | FREE_POINTER(p); 298 | } 299 | else { 300 | cSatipServer *tmp = new cSatipServer(srcAddrP, addrP, portP, modelP, filtersP, descP, quirkP); 301 | if (!serversM.Update(tmp)) { 302 | info("Adding server '%s|%s|%s' Bind: %s Filters: %s CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), !isempty(tmp->SrcAddress()) ? tmp->SrcAddress() : "default", !isempty(tmp->Filters()) ? tmp->Filters() : "none", tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none"); 303 | serversM.Add(tmp); 304 | } 305 | else 306 | DELETENULL(tmp); 307 | } 308 | } 309 | 310 | int cSatipDiscover::GetServerCount(void) 311 | { 312 | debug16("%s", __PRETTY_FUNCTION__); 313 | cMutexLock MutexLock(&mutexM); 314 | return serversM.Count(); 315 | } 316 | 317 | cSatipServer *cSatipDiscover::AssignServer(int deviceIdP, int sourceP, int transponderP, int systemP) 318 | { 319 | debug16("%s (%d, %d, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, sourceP, transponderP, systemP); 320 | cMutexLock MutexLock(&mutexM); 321 | return serversM.Assign(deviceIdP, sourceP, transponderP, systemP); 322 | } 323 | 324 | cSatipServer *cSatipDiscover::GetServer(int sourceP) 325 | { 326 | debug16("%s (%d)", __PRETTY_FUNCTION__, sourceP); 327 | cMutexLock MutexLock(&mutexM); 328 | return serversM.Find(sourceP); 329 | } 330 | 331 | cSatipServer *cSatipDiscover::GetServer(cSatipServer *serverP) 332 | { 333 | debug16("%s", __PRETTY_FUNCTION__); 334 | cMutexLock MutexLock(&mutexM); 335 | return serversM.Find(serverP); 336 | } 337 | 338 | cSatipServers *cSatipDiscover::GetServers(void) 339 | { 340 | debug16("%s", __PRETTY_FUNCTION__); 341 | cMutexLock MutexLock(&mutexM); 342 | return &serversM; 343 | } 344 | 345 | cString cSatipDiscover::GetServerString(cSatipServer *serverP) 346 | { 347 | debug16("%s", __PRETTY_FUNCTION__); 348 | cMutexLock MutexLock(&mutexM); 349 | return serversM.GetString(serverP); 350 | } 351 | 352 | cString cSatipDiscover::GetServerList(void) 353 | { 354 | debug16("%s", __PRETTY_FUNCTION__); 355 | cMutexLock MutexLock(&mutexM); 356 | return serversM.List(); 357 | } 358 | 359 | void cSatipDiscover::ActivateServer(cSatipServer *serverP, bool onOffP) 360 | { 361 | debug16("%s (, %d)", __PRETTY_FUNCTION__, onOffP); 362 | cMutexLock MutexLock(&mutexM); 363 | serversM.Activate(serverP, onOffP); 364 | } 365 | 366 | void cSatipDiscover::AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP) 367 | { 368 | debug16("%s (, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP); 369 | cMutexLock MutexLock(&mutexM); 370 | serversM.Attach(serverP, deviceIdP, transponderP); 371 | } 372 | 373 | void cSatipDiscover::DetachServer(cSatipServer *serverP, int deviceIdP, int transponderP) 374 | { 375 | debug16("%s (, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP); 376 | cMutexLock MutexLock(&mutexM); 377 | serversM.Detach(serverP, deviceIdP, transponderP); 378 | } 379 | 380 | bool cSatipDiscover::IsServerQuirk(cSatipServer *serverP, int quirkP) 381 | { 382 | debug16("%s (, %d)", __PRETTY_FUNCTION__, quirkP); 383 | cMutexLock MutexLock(&mutexM); 384 | return serversM.IsQuirk(serverP, quirkP); 385 | } 386 | 387 | bool cSatipDiscover::HasServerCI(cSatipServer *serverP) 388 | { 389 | debug16("%s", __PRETTY_FUNCTION__); 390 | cMutexLock MutexLock(&mutexM); 391 | return serversM.HasCI(serverP); 392 | } 393 | 394 | cString cSatipDiscover::GetSourceAddress(cSatipServer *serverP) 395 | { 396 | debug16("%s", __PRETTY_FUNCTION__); 397 | cMutexLock MutexLock(&mutexM); 398 | return serversM.GetSrcAddress(serverP); 399 | } 400 | 401 | cString cSatipDiscover::GetServerAddress(cSatipServer *serverP) 402 | { 403 | debug16("%s", __PRETTY_FUNCTION__); 404 | cMutexLock MutexLock(&mutexM); 405 | return serversM.GetAddress(serverP); 406 | } 407 | 408 | int cSatipDiscover::GetServerPort(cSatipServer *serverP) 409 | { 410 | debug16("%s", __PRETTY_FUNCTION__); 411 | cMutexLock MutexLock(&mutexM); 412 | return serversM.GetPort(serverP); 413 | } 414 | 415 | int cSatipDiscover::NumProvidedSystems(void) 416 | { 417 | debug16("%s", __PRETTY_FUNCTION__); 418 | cMutexLock MutexLock(&mutexM); 419 | return serversM.NumProvidedSystems(); 420 | } 421 | 422 | void cSatipDiscover::SetUrl(const char *urlP) 423 | { 424 | debug16("%s (%s)", __PRETTY_FUNCTION__, urlP); 425 | mutexM.Lock(); 426 | probeUrlListM.Insert(strdup(urlP)); 427 | mutexM.Unlock(); 428 | sleepM.Signal(); 429 | } 430 | -------------------------------------------------------------------------------- /discover.h: -------------------------------------------------------------------------------- 1 | /* 2 | * discover.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_DISCOVER_H 9 | #define __SATIP_DISCOVER_H 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include "common.h" 17 | #include "discoverif.h" 18 | #include "msearch.h" 19 | #include "server.h" 20 | #include "socket.h" 21 | 22 | class cSatipDiscoverServer : public cListObject { 23 | private: 24 | int ipPortM; 25 | int quirkM; 26 | cString srcAddressM; 27 | cString ipAddressM; 28 | cString descriptionM; 29 | cString modelM; 30 | cString filtersM; 31 | public: 32 | cSatipDiscoverServer(const char *srcAddressP, const char *ipAddressP, const int ipPortP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP) 33 | { 34 | srcAddressM = srcAddressP; ipAddressM = ipAddressP; ipPortM = ipPortP; modelM = modelP; filtersM = filtersP; descriptionM = descriptionP; quirkM = quirkP; 35 | } 36 | int IpPort(void) { return ipPortM; } 37 | int Quirk(void) { return quirkM; } 38 | const char *SrcAddress(void) { return *srcAddressM; } 39 | const char *IpAddress(void) { return *ipAddressM; } 40 | const char *Model(void) { return *modelM; } 41 | const char *Filters(void) { return *filtersM; } 42 | const char *Description(void) { return *descriptionM; } 43 | }; 44 | 45 | class cSatipDiscoverServers : public cList { 46 | }; 47 | 48 | class cSatipDiscover : public cThread, public cSatipDiscoverIf { 49 | private: 50 | enum { 51 | eSleepTimeoutMs = 500, // in milliseconds 52 | eConnectTimeoutMs = 1500, // in milliseconds 53 | eProbeTimeoutMs = 2000, // in milliseconds 54 | eProbeIntervalMs = 60000, // in milliseconds 55 | eCleanupTimeoutMs = 124000 // in milliseoonds 56 | }; 57 | static cSatipDiscover *instanceS; 58 | static size_t HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP); 59 | static size_t DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP); 60 | static int DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP); 61 | cMutex mutexM; 62 | cSatipMemoryBuffer headerBufferM; 63 | cSatipMemoryBuffer dataBufferM; 64 | cSatipMsearch msearchM; 65 | cStringList probeUrlListM; 66 | CURL *handleM; 67 | cCondWait sleepM; 68 | cTimeMs probeIntervalM; 69 | cSatipServers serversM; 70 | void Activate(void); 71 | void Deactivate(void); 72 | int ParseRtspPort(void); 73 | void ParseDeviceInfo(const char *addrP, const int portP); 74 | void AddServer(const char *srcAddrP, const char *addrP, const int portP, const char *modelP, const char *filtersP, const char *descP, const int quirkP); 75 | void Fetch(const char *urlP); 76 | // constructor 77 | cSatipDiscover(); 78 | // to prevent copy constructor and assignment 79 | cSatipDiscover(const cSatipDiscover&); 80 | cSatipDiscover& operator=(const cSatipDiscover&); 81 | 82 | protected: 83 | virtual void Action(void); 84 | 85 | public: 86 | static cSatipDiscover *GetInstance(void); 87 | static bool Initialize(cSatipDiscoverServers *serversP); 88 | static void Destroy(void); 89 | virtual ~cSatipDiscover(); 90 | void TriggerScan(void) { probeIntervalM.Set(0); } 91 | int GetServerCount(void); 92 | cSatipServer *AssignServer(int deviceIdP, int sourceP, int transponderP, int systemP); 93 | cSatipServer *GetServer(int sourceP); 94 | cSatipServer *GetServer(cSatipServer *serverP); 95 | cSatipServers *GetServers(void); 96 | cString GetServerString(cSatipServer *serverP); 97 | void ActivateServer(cSatipServer *serverP, bool onOffP); 98 | void AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP); 99 | void DetachServer(cSatipServer *serverP, int deviceIdP, int transponderP); 100 | bool IsServerQuirk(cSatipServer *serverP, int quirkP); 101 | bool HasServerCI(cSatipServer *serverP); 102 | cString GetServerAddress(cSatipServer *serverP); 103 | cString GetSourceAddress(cSatipServer *serverP); 104 | int GetServerPort(cSatipServer *serverP); 105 | cString GetServerList(void); 106 | int NumProvidedSystems(void); 107 | 108 | // for internal discover interface 109 | public: 110 | virtual void SetUrl(const char *urlP); 111 | }; 112 | 113 | #endif // __SATIP_DISCOVER_H 114 | -------------------------------------------------------------------------------- /discoverif.h: -------------------------------------------------------------------------------- 1 | /* 2 | * discoverif.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_DISCOVERIF_H 9 | #define __SATIP_DISCOVERIF_H 10 | 11 | class cSatipDiscoverIf { 12 | public: 13 | cSatipDiscoverIf() {} 14 | virtual ~cSatipDiscoverIf() {} 15 | virtual void SetUrl(const char *urlP) = 0; 16 | 17 | private: 18 | explicit cSatipDiscoverIf(const cSatipDiscoverIf&); 19 | cSatipDiscoverIf& operator=(const cSatipDiscoverIf&); 20 | }; 21 | 22 | #endif // __SATIP_DISCOVERIF_H 23 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * log.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_LOG_H 9 | #define __SATIP_LOG_H 10 | 11 | #include "config.h" 12 | 13 | #define error(x...) esyslog("SATIP-ERROR: " x) 14 | #define info(x...) isyslog("SATIP: " x) 15 | // 0x0001: Generic call stack 16 | #define debug1(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug1) ? dsyslog("SATIP1: " x) : void() ) 17 | // 0x0002: CURL data flow 18 | #define debug2(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug2) ? dsyslog("SATIP2: " x) : void() ) 19 | // 0x0004: Data parsing 20 | #define debug3(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug3) ? dsyslog("SATIP3: " x) : void() ) 21 | // 0x0008: Tuner state machine 22 | #define debug4(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug4) ? dsyslog("SATIP4: " x) : void() ) 23 | // 0x0010: RTSP responses 24 | #define debug5(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug5) ? dsyslog("SATIP5: " x) : void() ) 25 | // 0x0020: RTP throughput performance 26 | #define debug6(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug6) ? dsyslog("SATIP6: " x) : void() ) 27 | // 0x0040: RTP packet internals 28 | #define debug7(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug7) ? dsyslog("SATIP7: " x) : void() ) 29 | // 0x0080: Section filtering 30 | #define debug8(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug8) ? dsyslog("SATIP8: " x) : void() ) 31 | // 0x0100: Channel switching 32 | #define debug9(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug9) ? dsyslog("SATIP9: " x) : void() ) 33 | // 0x0200: RTCP packets 34 | #define debug10(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug10) ? dsyslog("SATIP10: " x) : void() ) 35 | // 0x0400: CI 36 | #define debug11(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug11) ? dsyslog("SATIP11: " x) : void() ) 37 | // 0x0800: Pids 38 | #define debug12(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug12) ? dsyslog("SATIP12: " x) : void() ) 39 | // 0x1000: Discovery 40 | #define debug13(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug13) ? dsyslog("SATIP13: " x) : void() ) 41 | // 0x2000: TBD 42 | #define debug14(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug14) ? dsyslog("SATIP14: " x) : void() ) 43 | // 0x4000: TBD 44 | #define debug15(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug15) ? dsyslog("SATIP15: " x) : void() ) 45 | // 0x8000; Extra call stack 46 | #define debug16(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug16) ? dsyslog("SATIP16: " x) : void() ) 47 | 48 | #endif // __SATIP_LOG_H 49 | -------------------------------------------------------------------------------- /msearch.c: -------------------------------------------------------------------------------- 1 | /* 2 | * msearch.c: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #include "config.h" 9 | #include "common.h" 10 | #include "discover.h" 11 | #include "log.h" 12 | #include "poller.h" 13 | #include "msearch.h" 14 | 15 | const char *cSatipMsearch::bcastAddressS = "239.255.255.250"; 16 | const char *cSatipMsearch::bcastMessageS = "M-SEARCH * HTTP/1.1\r\n" \ 17 | "HOST: 239.255.255.250:1900\r\n" \ 18 | "MAN: \"ssdp:discover\"\r\n" \ 19 | "ST: urn:ses-com:device:SatIPServer:1\r\n" \ 20 | "MX: 2\r\n\r\n"; 21 | 22 | cSatipMsearch::cSatipMsearch(cSatipDiscoverIf &discoverP) 23 | : discoverM(discoverP), 24 | bufferLenM(eProbeBufferSize), 25 | bufferM(MALLOC(unsigned char, bufferLenM)), 26 | registeredM(false) 27 | { 28 | if (bufferM) 29 | memset(bufferM, 0, bufferLenM); 30 | else 31 | error("Cannot create Msearch buffer!"); 32 | if (!Open(eDiscoveryPort, true)) 33 | error("Cannot open Msearch port!"); 34 | } 35 | 36 | cSatipMsearch::~cSatipMsearch() 37 | { 38 | FREE_POINTER(bufferM); 39 | } 40 | 41 | void cSatipMsearch::Probe(void) 42 | { 43 | debug1("%s", __PRETTY_FUNCTION__); 44 | if (!registeredM) { 45 | cSatipPoller::GetInstance()->Register(*this); 46 | registeredM = true; 47 | } 48 | // Send two queries with one second interval 49 | Write(bcastAddressS, reinterpret_cast(bcastMessageS), strlen(bcastMessageS)); 50 | cCondWait::SleepMs(1000); 51 | Write(bcastAddressS, reinterpret_cast(bcastMessageS), strlen(bcastMessageS)); 52 | } 53 | 54 | int cSatipMsearch::GetFd(void) 55 | { 56 | return Fd(); 57 | } 58 | 59 | void cSatipMsearch::Process(void) 60 | { 61 | debug16("%s", __PRETTY_FUNCTION__); 62 | if (bufferM) { 63 | int length; 64 | while ((length = Read(bufferM, bufferLenM)) > 0) { 65 | bufferM[min(length, int(bufferLenM - 1))] = 0; 66 | debug13("%s len=%d buf=%s", __PRETTY_FUNCTION__, length, bufferM); 67 | bool status = false, valid = false; 68 | char *s, *p = reinterpret_cast(bufferM), *location = NULL; 69 | char *r = strtok_r(p, "\r\n", &s); 70 | while (r) { 71 | debug13("%s r=%s", __PRETTY_FUNCTION__, r); 72 | // Check the status code 73 | // HTTP/1.1 200 OK 74 | if (!status && startswith(r, "HTTP/1.1 200 OK")) 75 | status = true; 76 | if (status) { 77 | // Check the location data 78 | // LOCATION: http://192.168.0.115:8888/octonet.xml 79 | if (strcasestr(r, "LOCATION:") == r) { 80 | location = compactspace(r + 9); 81 | debug1("%s location='%s'", __PRETTY_FUNCTION__, location); 82 | } 83 | // Check the source type 84 | // ST: urn:ses-com:device:SatIPServer:1 85 | else if (strcasestr(r, "ST:") == r) { 86 | char *st = compactspace(r + 3); 87 | if (strstr(st, "urn:ses-com:device:SatIPServer:1")) 88 | valid = true; 89 | debug1("%s st='%s'", __PRETTY_FUNCTION__, st); 90 | } 91 | // Check whether all the required data is found 92 | if (valid && !isempty(location)) { 93 | discoverM.SetUrl(location); 94 | break; 95 | } 96 | } 97 | r = strtok_r(NULL, "\r\n", &s); 98 | } 99 | } 100 | } 101 | } 102 | 103 | void cSatipMsearch::Process(unsigned char *dataP, int lengthP) 104 | { 105 | debug16("%s", __PRETTY_FUNCTION__); 106 | } 107 | 108 | cString cSatipMsearch::ToString(void) const 109 | { 110 | return "MSearch"; 111 | } 112 | -------------------------------------------------------------------------------- /msearch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * msearch.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_MSEARCH_H_ 9 | #define __SATIP_MSEARCH_H_ 10 | 11 | #include "discoverif.h" 12 | #include "socket.h" 13 | #include "pollerif.h" 14 | 15 | class cSatipMsearch : public cSatipSocket, public cSatipPollerIf { 16 | private: 17 | enum { 18 | eProbeBufferSize = 1024, // in bytes 19 | eDiscoveryPort = 1900, 20 | }; 21 | static const char *bcastAddressS; 22 | static const char *bcastMessageS; 23 | cSatipDiscoverIf &discoverM; 24 | unsigned int bufferLenM; 25 | unsigned char *bufferM; 26 | bool registeredM; 27 | 28 | public: 29 | explicit cSatipMsearch(cSatipDiscoverIf &discoverP); 30 | virtual ~cSatipMsearch(); 31 | void Probe(void); 32 | 33 | // for internal poller interface 34 | public: 35 | virtual int GetFd(void); 36 | virtual void Process(void); 37 | virtual void Process(unsigned char *dataP, int lengthP); 38 | virtual cString ToString(void) const; 39 | }; 40 | 41 | #endif /* __SATIP_MSEARCH_H_ */ 42 | -------------------------------------------------------------------------------- /param.c: -------------------------------------------------------------------------------- 1 | /* 2 | * param.c: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | #include "common.h" 11 | #include "param.h" 12 | 13 | // --- cSatipParameterMaps ---------------------------------------------------- 14 | 15 | struct tSatipParameterMap { 16 | int driverValue; 17 | const char *satipString; 18 | }; 19 | 20 | static const tSatipParameterMap SatipBandwidthValues[] = { 21 | { 5000000, "&bw=5" }, 22 | { 6000000, "&bw=6" }, 23 | { 7000000, "&bw=7" }, 24 | { 8000000, "&bw=8" }, 25 | { 10000000, "&bw=10" }, 26 | { 1712000, "&bw=1.712" }, 27 | { -1, NULL } 28 | }; 29 | 30 | static const tSatipParameterMap SatipPilotValues[] = { 31 | { PILOT_OFF, "&plts=off" }, 32 | { PILOT_ON, "&plts=on" }, 33 | { PILOT_AUTO, "" }, 34 | { -1, NULL } 35 | }; 36 | 37 | static const tSatipParameterMap SatipSisoMisoValues[] = { 38 | { 0, "&sm=0" }, 39 | { 1, "&sm=1" }, 40 | { -1, NULL } 41 | }; 42 | 43 | static const tSatipParameterMap SatipCodeRateValues[] = { 44 | { FEC_NONE, "" }, 45 | { FEC_1_2, "&fec=12" }, 46 | { FEC_2_3, "&fec=23" }, 47 | { FEC_3_4, "&fec=34" }, 48 | { FEC_3_5, "&fec=35" }, 49 | { FEC_4_5, "&fec=45" }, 50 | { FEC_5_6, "&fec=56" }, 51 | { FEC_6_7, "&fec=67" }, 52 | { FEC_7_8, "&fec=78" }, 53 | { FEC_8_9, "&fec=89" }, 54 | { FEC_9_10, "&fec=910" }, 55 | { FEC_AUTO, "" }, 56 | { -1, NULL } 57 | }; 58 | 59 | static const tSatipParameterMap SatipModulationValues[] = { 60 | { QPSK, "&mtype=qpsk" }, 61 | { PSK_8, "&mtype=8psk" }, 62 | { APSK_16, "&mtype=16apsk" }, 63 | { APSK_32, "&mtype=32apsk" }, 64 | { VSB_8, "&mtype=8vsb" }, 65 | { VSB_16, "&mtype=16vsb" }, 66 | { QAM_16, "&mtype=16qam" }, 67 | { QAM_64, "&mtype=64qam" }, 68 | { QAM_128, "&mtype=128qam" }, 69 | { QAM_256, "&mtype=256qam" }, 70 | { QAM_AUTO, "" }, 71 | { -1, NULL } 72 | }; 73 | 74 | static const tSatipParameterMap SatipSystemValuesSat[] = { 75 | { 0, "&msys=dvbs" }, 76 | { 1, "&msys=dvbs2" }, 77 | { -1, NULL } 78 | }; 79 | 80 | static const tSatipParameterMap SatipSystemValuesTerrestrial[] = { 81 | { 0, "&msys=dvbt" }, 82 | { 1, "&msys=dvbt2" }, 83 | { -1, NULL } 84 | }; 85 | 86 | static const tSatipParameterMap SatipSystemValuesCable[] = { 87 | { 0, "&msys=dvbc" }, 88 | { 1, "&msys=dvbc2" }, 89 | { -1, NULL } 90 | }; 91 | 92 | static const tSatipParameterMap SatipSystemValuesAtsc[] = { 93 | { 0, "&msys=atsc" }, 94 | { -1, NULL } 95 | }; 96 | 97 | static const tSatipParameterMap SatipTransmissionValues[] = { 98 | { TRANSMISSION_MODE_1K, "&tmode=1k" }, 99 | { TRANSMISSION_MODE_2K, "&tmode=2k" }, 100 | { TRANSMISSION_MODE_4K, "&tmode=4k" }, 101 | { TRANSMISSION_MODE_8K, "&tmode=8k" }, 102 | { TRANSMISSION_MODE_16K, "&tmode=16k" }, 103 | { TRANSMISSION_MODE_32K, "&tmode=32k" }, 104 | { TRANSMISSION_MODE_AUTO, "" }, 105 | { -1, NULL } 106 | }; 107 | 108 | static const tSatipParameterMap SatipGuardValues[] = { 109 | { GUARD_INTERVAL_1_4, "&gi=14" }, 110 | { GUARD_INTERVAL_1_8, "&gi=18" }, 111 | { GUARD_INTERVAL_1_16, "&gi=116" }, 112 | { GUARD_INTERVAL_1_32, "&gi=132" }, 113 | { GUARD_INTERVAL_1_128, "&gi=1128" }, 114 | { GUARD_INTERVAL_19_128, "&gi=19128" }, 115 | { GUARD_INTERVAL_19_256, "&gi=19256" }, 116 | { GUARD_INTERVAL_AUTO, "" }, 117 | { -1, NULL } 118 | }; 119 | 120 | static const tSatipParameterMap SatipRollOffValues[] = { 121 | { ROLLOFF_AUTO, "" }, 122 | { ROLLOFF_20, "&ro=0.20" }, 123 | { ROLLOFF_25, "&ro=0.25" }, 124 | { ROLLOFF_35, "&ro=0.35" }, 125 | { -1, NULL } 126 | }; 127 | 128 | static const tSatipParameterMap SatipInversionValues[] = { 129 | { INVERSION_AUTO, "" }, 130 | { INVERSION_OFF, "&specinv=0" }, 131 | { INVERSION_ON, "&specinv=1" }, 132 | { -1, NULL } 133 | }; 134 | 135 | static int SatipUserIndex(int valueP, const tSatipParameterMap *mapP) 136 | { 137 | const tSatipParameterMap *map = mapP; 138 | while (map && map->driverValue != -1) { 139 | if (map->driverValue == valueP) 140 | return map - mapP; 141 | map++; 142 | } 143 | return -1; 144 | } 145 | 146 | static int PrintUrlString(char *bufP, int lenP, int valueP, const tSatipParameterMap *mapP) 147 | { 148 | int n = SatipUserIndex(valueP, mapP); 149 | return ((n >= 0) && (lenP > 0)) ? snprintf(bufP, lenP, "%s", mapP[n].satipString) : 0; 150 | } 151 | 152 | cString GetTransponderUrlParameters(const cChannel *channelP) 153 | { 154 | if (channelP) { 155 | char buffer[255]; 156 | cDvbTransponderParameters dtp(channelP->Parameters()); 157 | int DataSlice = 0; 158 | int C2TuningFrequencyType = 0; 159 | float freq = channelP->Frequency(); 160 | char type = cSource::ToChar(channelP->Source()); 161 | cSource *source = Sources.Get(channelP->Source()); 162 | int src = (strchr("S", type) && source) ? atoi(source->Description()) : 1; 163 | char *q = buffer; 164 | *q = 0; 165 | // Scale down frequencies to MHz 166 | while (freq > 20000L) 167 | freq /= 1000L; 168 | #define ST(s) if (strchr(s, type) && (strchr(s, '0' + dtp.System() + 1) || strchr(s, '*'))) 169 | #define STBUFLEFT (sizeof(buffer) - (q - buffer)) 170 | ST(" S 1") { // to comply with SAT>IP protocol specification 1.2.2 171 | dtp.SetPilot(PILOT_OFF); 172 | dtp.SetModulation(QPSK); 173 | dtp.SetRollOff(ROLLOFF_35); 174 | } 175 | if ((channelP->Rid() % 100) > 0) 176 | q += snprintf(q, STBUFLEFT, "&fe=%d", channelP->Rid() % 100); 177 | ST(" S *") q += snprintf(q, STBUFLEFT, "&src=%d", ((src > 0) && (src <= 255)) ? src : 1); 178 | if (freq >= 0L) 179 | q += snprintf(q, STBUFLEFT, "&freq=%s", *dtoa(freq, "%lg")); 180 | ST(" S *") q += snprintf(q, STBUFLEFT, "&pol=%c", tolower(dtp.Polarization())); 181 | ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(), SatipRollOffValues); 182 | ST(" C 2") q += snprintf(q, STBUFLEFT, "&c2tft=%d", C2TuningFrequencyType); 183 | ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(), SatipBandwidthValues); 184 | ST(" C 2") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(), SatipBandwidthValues); 185 | ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesSat); 186 | ST(" C *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesCable); 187 | ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesTerrestrial); 188 | ST("A *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesAtsc); 189 | ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Transmission(), SatipTransmissionValues); 190 | ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues); 191 | ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues); 192 | ST(" C 1") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues); 193 | ST("A *") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues); 194 | ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.Pilot(), SatipPilotValues); 195 | ST(" S *") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate()); 196 | ST(" C 1") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate()); 197 | ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Guard(), SatipGuardValues); 198 | ST(" CST*") q += PrintUrlString(q, STBUFLEFT, dtp.CoderateH(), SatipCodeRateValues); 199 | ST(" C 2") q += snprintf(q, STBUFLEFT, "&ds=%d", DataSlice); 200 | ST(" C T2") q += snprintf(q, STBUFLEFT, "&plp=%d", dtp.StreamId()); 201 | ST(" T2") q += snprintf(q, STBUFLEFT, "&t2id=%d", dtp.T2SystemId()); 202 | ST(" T2") q += PrintUrlString(q, STBUFLEFT, dtp.SisoMiso(), SatipSisoMisoValues); 203 | ST(" C 1") q += PrintUrlString(q, STBUFLEFT, dtp.Inversion(), SatipInversionValues); 204 | ST("A *") q += PrintUrlString(q, STBUFLEFT, dtp.Inversion(), SatipInversionValues); 205 | #undef ST 206 | return &buffer[1]; 207 | } 208 | return NULL; 209 | } 210 | 211 | cString GetTnrUrlParameters(const cChannel *channelP) 212 | { 213 | if (channelP) { 214 | cDvbTransponderParameters dtp(channelP->Parameters()); 215 | eTrackType track = cDevice::PrimaryDevice()->GetCurrentAudioTrack(); 216 | 217 | // TunerType: Byte; 218 | // 0 = cable, 1 = satellite, 2 = terrestrial, 3 = atsc, 4 = iptv, 5 = stream (URL, DVBViewer GE) 219 | int TunerType = 0; 220 | if (channelP->IsCable()) 221 | TunerType = 0; 222 | else if (channelP->IsSat()) 223 | TunerType = 1; 224 | else if (channelP->IsTerr()) 225 | TunerType = 2; 226 | else if (channelP->IsAtsc()) 227 | TunerType = 3; 228 | 229 | // Frequency: DWord; 230 | // DVB-S: MHz if < 1000000, kHz if >= 1000000 231 | // DVB-T/C, ATSC: kHz 232 | // IPTV: IP address Byte3.Byte2.Byte1.Byte0 233 | int Frequency = channelP->Frequency() / 1000; 234 | 235 | // Symbolrate: DWord; 236 | // DVB S/C: in kSym/s 237 | // DVB-T, ATSC: 0 238 | // IPTV: Port 239 | int Symbolrate = (channelP->IsSat() || channelP->IsCable()) ? channelP->Srate() : 0; 240 | 241 | // LNB_LOF: Word; 242 | // DVB-S: Local oscillator frequency of the LNB 243 | // DVB-T/C, ATSC: 0 244 | // IPTV: Byte0 and Byte1 of Source IP 245 | int LNB_LOF = channelP->IsSat() ? Setup.LnbSLOF : 0; 246 | 247 | // Tone: Byte; 248 | // 0 = off, 1 = 22 khz 249 | int Tone = (channelP->Frequency() < Setup.LnbSLOF) ? 0 : 1; 250 | 251 | // Polarity: Byte; 252 | // DVB-S polarity: 0 = horizontal, 1 = vertical, 2 = circular left, 3 = circular right 253 | // DVB-C modulation: 0 = Auto, 1 = 16QAM, 2 = 32QAM, 3 = 64QAM, 4 = 128QAM, 5 = 256 QAM 254 | // DVB-T bandwidth: 0 = 6 MHz, 1 = 7 MHz, 2 = 8 MHz 255 | // IPTV: Byte3 of SourceIP 256 | int Polarity = 0; 257 | if (channelP->IsSat()) { 258 | switch (tolower(dtp.Polarization())) { 259 | case 'h': 260 | Polarity = 0; 261 | break; 262 | case 'v': 263 | Polarity = 1; 264 | break; 265 | case 'l': 266 | Polarity = 2; 267 | break; 268 | case 'r': 269 | Polarity = 3; 270 | break; 271 | default: 272 | break; 273 | } 274 | } 275 | else if (channelP->IsCable()) { 276 | switch (dtp.Modulation()) { 277 | case 999: 278 | Polarity = 0; 279 | break; 280 | case 16: 281 | Polarity = 1; 282 | break; 283 | case 32: 284 | Polarity = 2; 285 | break; 286 | case 64: 287 | Polarity = 3; 288 | break; 289 | case 128: 290 | Polarity = 4; 291 | break; 292 | case 256: 293 | Polarity = 5; 294 | break; 295 | default: 296 | break; 297 | } 298 | } 299 | else if (channelP->IsTerr()) { 300 | switch (dtp.Bandwidth()) { 301 | case 6: 302 | Polarity = 0; 303 | break; 304 | case 7: 305 | Polarity = 1; 306 | break; 307 | case 8: 308 | Polarity = 2; 309 | break; 310 | default: 311 | break; 312 | } 313 | } 314 | 315 | // DiSEqC: Byte; 316 | // 0 = None 317 | // 1 = Pos A (mostly translated to PosA/OptA) 318 | // 2 = Pos B (mostly translated to PosB/OptA) 319 | // 3 = PosA/OptA 320 | // 4 = PosB/OptA 321 | // 5 = PosA/OptB 322 | // 6 = PosB/OptB 323 | // 7 = Preset Position (DiSEqC 1.2, see DiSEqCExt) 324 | // 8 = Angular Position (DiSEqC 1.2, see DiSEqCExt) 325 | // 9 = DiSEqC Command Sequence (see DiSEqCExt) 326 | int DiSEqC = 0; 327 | 328 | // FEC: Byte; 329 | // 0 = Auto 330 | // 1 = 1/2 331 | // 2 = 2/3 332 | // 3 = 3/4 333 | // 4 = 5/6 334 | // 5 = 7/8 335 | // 6 = 8/9 336 | // 7 = 3/5 337 | // 8 = 4/5 338 | // 9 = 9/10 339 | // IPTV: Byte2 of SourceIP 340 | // DVB C/T, ATSC: 0 341 | int FEC = 0; 342 | if (channelP->IsSat()) { 343 | switch (dtp.CoderateH()) { 344 | case 999: 345 | FEC = 0; 346 | break; 347 | case 12: 348 | FEC = 1; 349 | break; 350 | case 23: 351 | FEC = 2; 352 | break; 353 | case 34: 354 | FEC = 3; 355 | break; 356 | case 56: 357 | FEC = 4; 358 | break; 359 | case 78: 360 | FEC = 5; 361 | break; 362 | case 89: 363 | FEC = 6; 364 | break; 365 | case 35: 366 | FEC = 7; 367 | break; 368 | case 45: 369 | FEC = 8; 370 | break; 371 | case 910: 372 | FEC = 9; 373 | break; 374 | default: 375 | break; 376 | } 377 | } 378 | 379 | // Audio_PID: Word; 380 | int Audio_PID = channelP->Apid(0); 381 | if (IS_AUDIO_TRACK(track)) 382 | Audio_PID = channelP->Apid(int(track - ttAudioFirst)); 383 | else if (IS_DOLBY_TRACK(track)) 384 | Audio_PID = channelP->Dpid(int(track - ttDolbyFirst)); 385 | 386 | // Video_PID: Word; 387 | int Video_PID = channelP->Vpid(); 388 | 389 | // PMT_PID: Word; 390 | int PMT_PID = channelP->Ppid(); 391 | 392 | // Service_ID: Word; 393 | int Service_ID = channelP->Sid(); 394 | 395 | // SatModulation: Byte; 396 | // Bit 0..1: satellite modulation. 0 = Auto, 1 = QPSK, 2 = 8PSK, 3 = 16QAM or APSK for DVB-S2 397 | // Bit 2: modulation system. 0 = DVB-S/T/C, 1 = DVB-S2/T2/C2 398 | // Bit 3..4: DVB-S2: roll-off. 0 = 0.35, 1 = 0.25, 2 = 0.20, 3 = reserved 399 | // Bit 5..6: spectral inversion, 0 = undefined, 1 = auto, 2 = normal, 3 = inverted 400 | // Bit 7: DVB-S2: pilot symbols, 0 = off, 1 = on 401 | // DVB-T2: DVB-T2 Lite, 0 = off, 1 = on 402 | int SatModulation = 0; 403 | if (channelP->IsSat() && dtp.System()) { 404 | switch (dtp.Modulation()) { 405 | case 999: 406 | SatModulation |= (0 & 0x3) << 0; 407 | break; 408 | case 2: 409 | SatModulation |= (1 & 0x3) << 0; 410 | break; 411 | case 5: 412 | SatModulation |= (2 & 0x3) << 0; 413 | break; 414 | case 6: 415 | SatModulation |= (3 & 0x3) << 0; 416 | break; 417 | default: 418 | break; 419 | } 420 | } 421 | SatModulation |= (dtp.System() & 0x1) << 2; 422 | if (channelP->IsSat() && dtp.System()) { 423 | switch (dtp.RollOff()) { 424 | case 35: 425 | SatModulation |= (0 & 0x3) << 3; 426 | break; 427 | case 25: 428 | SatModulation |= (1 & 0x3) << 3; 429 | break; 430 | case 20: 431 | SatModulation |= (2 & 0x3) << 3; 432 | break; 433 | default: 434 | break; 435 | } 436 | } 437 | switch (dtp.Inversion()) { 438 | case 999: 439 | SatModulation |= (1 & 0x3) << 5; 440 | break; 441 | case 0: 442 | SatModulation |= (2 & 0x3) << 5; 443 | break; 444 | case 1: 445 | SatModulation |= (3 & 0x3) << 5; 446 | break; 447 | default: 448 | break; 449 | } 450 | if (channelP->IsSat() && dtp.System()) { 451 | switch (dtp.Pilot()) { 452 | case 0: 453 | SatModulation |= (0 & 0x1) << 7; 454 | break; 455 | case 1: 456 | SatModulation |= (1 & 0x1) << 7; 457 | break; 458 | default: 459 | break; 460 | } 461 | } 462 | 463 | // DiSEqCExt: Word; 464 | // DiSEqC Extension, meaning depends on DiSEqC 465 | // DiSEqC = 0..6: 0 466 | // DiSEqC = 7: Preset Position (DiSEqC 1.2) 467 | // DiSEqC = 8: Orbital Position (DiSEqC 1.2, USALS, for calculating motor angle) 468 | // Same format as OrbitalPos above 469 | // DiSEQC = 9: Orbital Position referencing DiSEqC sequence defined in DiSEqC.xml/ini 470 | // Same format as OrbitalPos above 471 | int DiSEqCExt = 0; 472 | 473 | // Flags: Byte; 474 | // Bit 0: 1 = encrypted channel 475 | // Bit 1: reserved, set to 0 476 | // Bit 2: 1 = channel broadcasts RDS data 477 | // Bit 3: 1 = channel is a video service (even if the Video PID is temporarily = 0) 478 | // Bit 4: 1 = channel is an audio service (even if the Audio PID is temporarily = 0) 479 | // Bit 5: 1 = audio has a different samplerate than 48 KHz 480 | // Bit 6: 1 = bandstacking, internally polarisation is always set to H 481 | // Bit 7: 1 = channel entry is an additional audio track of the preceding 482 | // channel with bit 7 = 0 483 | int Flags = (channelP->Ca() > 0xFF) ? 1 : 0; 484 | 485 | // ChannelGroup: Byte; 486 | // 0 = Group A, 1 = Group B, 2 = Group C etc. 487 | int ChannelGroup = 0; 488 | 489 | // TransportStream_ID: Word; 490 | int TransportStream_ID = channelP->Tid(); 491 | 492 | // OriginalNetwork_ID: Word; 493 | int OriginalNetwork_ID = channelP->Nid(); 494 | 495 | // Substream: Word; 496 | // DVB-S/C/T, ATSC, IPTV: 0 497 | // DVB-T2: 0 = PLP_ID not set, 1..256: PLP_ID + 1, 257... reserved 498 | int Substream = (channelP->IsTerr() && dtp.System()) ? dtp.StreamId() - 1 : 0; 499 | 500 | // OrbitalPos: Word; 501 | // DVB-S: orbital position x 10, 0 = undefined, 1..1800 east, 1801..3599 west (1°W = 3599) 502 | // DVB-C: 4000..4999 503 | // DVB-T: 5000..5999 504 | // ATSC: 6000..6999 505 | // IPTV: 7000..7999 506 | // Stream: 8000..8999 507 | int OrbitalPos = 0; 508 | if (channelP->IsSat()) { 509 | OrbitalPos = cSource::Position(channelP->Source()); 510 | if (OrbitalPos != 3600) 511 | OrbitalPos += 1800; 512 | } 513 | 514 | return cString::sprintf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", 515 | TunerType, Frequency, Symbolrate, LNB_LOF, Tone, Polarity, DiSEqC, FEC, Audio_PID, Video_PID, PMT_PID, Service_ID, 516 | SatModulation, DiSEqCExt, Flags, ChannelGroup, TransportStream_ID, OriginalNetwork_ID, Substream, OrbitalPos); 517 | } 518 | return NULL; 519 | } 520 | -------------------------------------------------------------------------------- /param.h: -------------------------------------------------------------------------------- 1 | /* 2 | * param.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_PARAM_H 9 | #define __SATIP_PARAM_H 10 | 11 | #include "common.h" 12 | 13 | cString GetTransponderUrlParameters(const cChannel *channelP); 14 | cString GetTnrUrlParameters(const cChannel *channelP); 15 | 16 | #endif // __SATIP_PARAM_H 17 | -------------------------------------------------------------------------------- /po/ca_ES.po: -------------------------------------------------------------------------------- 1 | # VDR plugin language source file. 2 | # Copyright (C) 2007-2019 Rolf Ahrenberg 3 | # This file is distributed under the same license as the satip package. 4 | # Gabriel Bonich, 2014-2017 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: vdr-satip 2.4.0\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2019-10-27 19:12+0200\n" 11 | "PO-Revision-Date: 2019-10-27 10:27+0200\n" 12 | "Last-Translator: Gabriel Bonich \n" 13 | "Language-Team: Catalan \n" 14 | "Language: ca\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | msgid "PAT (0x00)" 20 | msgstr "PAT (0x00)" 21 | 22 | msgid "NIT (0x40)" 23 | msgstr "NIT (0x40)" 24 | 25 | msgid "SDT (0x42)" 26 | msgstr "SDT (0x42)" 27 | 28 | msgid "EIT (0x4E/0x4F/0x5X/0x6X)" 29 | msgstr "EIT (0x4E/0x4F/0x5X/0x6X)" 30 | 31 | msgid "TDT (0x70)" 32 | msgstr "TDT (0x70)" 33 | 34 | msgid "SAT>IP information not available!" 35 | msgstr "SAT>IP Informació no disponible!" 36 | 37 | msgid "SAT>IP Devices" 38 | msgstr "SAT>IP Dispositius" 39 | 40 | msgid "SAT>IP Server" 41 | msgstr "SAT>IP Server" 42 | 43 | msgid "Address" 44 | msgstr "Adressa" 45 | 46 | msgid "Model" 47 | msgstr "Model" 48 | 49 | msgid "Description" 50 | msgstr "Descripció" 51 | 52 | msgid "CI extension" 53 | msgstr "Extensió CI" 54 | 55 | msgid "Creation date" 56 | msgstr "Creació de data" 57 | 58 | msgid "SAT>IP Device Status" 59 | msgstr "SAT>IP Estat Dispositiu" 60 | 61 | msgid "SAT>IP Information" 62 | msgstr "SAT>IP Informació" 63 | 64 | msgid "General" 65 | msgstr "General" 66 | 67 | msgid "Pids" 68 | msgstr "Pids" 69 | 70 | msgid "Filters" 71 | msgstr "Filtres" 72 | 73 | msgid "Bits/bytes" 74 | msgstr "Bits/Bytes" 75 | 76 | msgid "off" 77 | msgstr "Apagat" 78 | 79 | msgid "low" 80 | msgstr "Baix" 81 | 82 | msgid "normal" 83 | msgstr "Normal" 84 | 85 | msgid "high" 86 | msgstr "Alt" 87 | 88 | msgid "Unicast" 89 | msgstr "Unicast" 90 | 91 | msgid "Multicast" 92 | msgstr "Multicast" 93 | 94 | msgid "RTP-over-TCP" 95 | msgstr "RTP-per sobre-TCP" 96 | 97 | msgid "Button$Devices" 98 | msgstr "Dispositius" 99 | 100 | msgid "Operating mode" 101 | msgstr "Mode de operació" 102 | 103 | msgid "" 104 | "Define the used operating mode for all SAT>IP devices:\n" 105 | "\n" 106 | "off - devices are disabled\n" 107 | "low - devices are working at the lowest priority\n" 108 | "normal - devices are working within normal parameters\n" 109 | "high - devices are working at the highest priority" 110 | msgstr "" 111 | "Defineig la manera de operar els Dispositius SAT>IP:\n" 112 | "\n" 113 | "Apagat - Dispositius desactivats\n" 114 | "Baix - Dispositius treballan a baixa prioritat\n" 115 | "Normal - Dispositius treballan en parametres normals\n" 116 | "Alta - Dispositius treballan a prioritat Alta" 117 | 118 | msgid "Enable CI extension" 119 | msgstr "Habilita la extenció CI" 120 | 121 | msgid "" 122 | "Define whether a CI extension shall be used.\n" 123 | "\n" 124 | "This setting enables integrated CI/CAM handling found in some SAT>IP hardware (e.g. Digital Devices OctopusNet)." 125 | msgstr "" 126 | "Definir si s'utilitzarà una extensió de CI.\n" 127 | "\n" 128 | "Aquesta configuració permet utilitzar CI/CAM integrat que es troba en alguns equips SAT>IP (ex. Digital Devices OctopusNet)." 129 | 130 | msgid "CI/CAM" 131 | msgstr "CI/CAM" 132 | 133 | msgid "" 134 | "Define a desired CAM type for the CI slot.\n" 135 | "\n" 136 | "The '---' option lets SAT>IP hardware do the auto-selection." 137 | msgstr "" 138 | "Definir quin tipus de CAM vols per a la ranura CI.\n" 139 | "\n" 140 | "L'opció '---' permet l'equip SAT>IP fer la selecció automàtica." 141 | 142 | msgid "Enable EPG scanning" 143 | msgstr "Activa Escanneig EPG" 144 | 145 | msgid "" 146 | "Define whether the EPG background scanning shall be used.\n" 147 | "\n" 148 | "This setting disables the automatic EIT scanning functionality for all SAT>IP devices." 149 | msgstr "" 150 | "Definir si s'utilitzarà l'anàlisi en segon pla del EPG.\n" 151 | "\n" 152 | "Aquesta configuració desactiva la funcionalitat d'escaneig EIT automàtica per a tots els dispositius SAT>IP." 153 | 154 | msgid "Disabled sources" 155 | msgstr "Desactiva entrades" 156 | 157 | msgid "none" 158 | msgstr "no" 159 | 160 | msgid "" 161 | "Define number of sources to be disabled.\n" 162 | "\n" 163 | "SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here." 164 | msgstr "" 165 | "Definir nombre de entrades que es desactiven.\n" 166 | "\n" 167 | "SAT>IP els servidors podrien no tenir totes les posicions dels satèl·lits disponibles i aquestes entrades poden ser la llista negra." 168 | 169 | msgid "Define a source to be blacklisted." 170 | msgstr "Definir una entrada a la llista negra" 171 | 172 | msgid "Disabled filters" 173 | msgstr "Desactiva filtres" 174 | 175 | msgid "" 176 | "Define number of section filters to be disabled.\n" 177 | "\n" 178 | "Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process." 179 | msgstr "" 180 | "Defineix el numero de filtres de secció que seran deshabilitats.\n" 181 | "\n" 182 | "Alguns filtres de secció podrien provocar un comportament no desitjat a VDR, com sincronitzar malament l'hora. Posant aquests filtres a la llista negra, aqui, la secció de dades útil pot ser deixada intacta pel seu procès en el VDR." 183 | 184 | msgid "Filter" 185 | msgstr "Filtra" 186 | 187 | msgid "Define an ill-behaving filter to be blacklisted." 188 | msgstr "Definir un filtre mal comportar a la llista negra." 189 | 190 | msgid "Transport mode" 191 | msgstr "Tipus de Transmissió" 192 | 193 | msgid "" 194 | "Define which transport mode shall be used.\n" 195 | "\n" 196 | "Unicast, Multicast, RTP-over-TCP" 197 | msgstr "" 198 | 199 | msgid "Enable frontend reuse" 200 | msgstr "" 201 | 202 | msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled." 203 | msgstr "" 204 | 205 | msgid "Active SAT>IP servers:" 206 | msgstr "Activa SAT>IP servers:" 207 | 208 | msgid "Help" 209 | msgstr "Ajuda" 210 | -------------------------------------------------------------------------------- /po/de_DE.po: -------------------------------------------------------------------------------- 1 | # VDR plugin language source file. 2 | # Copyright (C) 2007-2019 Rolf Ahrenberg 3 | # This file is distributed under the same license as the satip package. 4 | # Frank Neumann, 2014-2017 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: vdr-satip 2.4.0\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2019-10-27 19:12+0200\n" 11 | "PO-Revision-Date: 2019-10-27 10:27+0200\n" 12 | "Last-Translator: Frank Neumann \n" 13 | "Language-Team: German \n" 14 | "Language: de\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | msgid "PAT (0x00)" 20 | msgstr "PAT (0x00)" 21 | 22 | msgid "NIT (0x40)" 23 | msgstr "NIT (0x40)" 24 | 25 | msgid "SDT (0x42)" 26 | msgstr "SDT (0x42)" 27 | 28 | msgid "EIT (0x4E/0x4F/0x5X/0x6X)" 29 | msgstr "EIT (0x4E/0x4F/0x5X/0x6X)" 30 | 31 | msgid "TDT (0x70)" 32 | msgstr "TDT (0x70)" 33 | 34 | msgid "SAT>IP information not available!" 35 | msgstr "Keine SAT>IP Informationen verfügbar!" 36 | 37 | msgid "SAT>IP Devices" 38 | msgstr "SAT>IP Geräte" 39 | 40 | msgid "SAT>IP Server" 41 | msgstr "SAT>IP Server" 42 | 43 | msgid "Address" 44 | msgstr "Adresse" 45 | 46 | msgid "Model" 47 | msgstr "Modell" 48 | 49 | msgid "Description" 50 | msgstr "Beschreibung" 51 | 52 | msgid "CI extension" 53 | msgstr "CI Erweiterung" 54 | 55 | msgid "Creation date" 56 | msgstr "Zeitpunkt der Erstellung" 57 | 58 | msgid "SAT>IP Device Status" 59 | msgstr "SAT>IP Gerätestatus" 60 | 61 | msgid "SAT>IP Information" 62 | msgstr "SAT>IP Informationen" 63 | 64 | msgid "General" 65 | msgstr "Allgemein" 66 | 67 | msgid "Pids" 68 | msgstr "Pids" 69 | 70 | msgid "Filters" 71 | msgstr "Filter" 72 | 73 | msgid "Bits/bytes" 74 | msgstr "Bits/Bytes" 75 | 76 | msgid "off" 77 | msgstr "aus" 78 | 79 | msgid "low" 80 | msgstr "niedrig" 81 | 82 | msgid "normal" 83 | msgstr "normal" 84 | 85 | msgid "high" 86 | msgstr "hoch" 87 | 88 | msgid "Unicast" 89 | msgstr "Unicast" 90 | 91 | msgid "Multicast" 92 | msgstr "Multicast" 93 | 94 | msgid "RTP-over-TCP" 95 | msgstr "RTP-over-TCP" 96 | 97 | msgid "Button$Devices" 98 | msgstr "Geräte" 99 | 100 | msgid "Operating mode" 101 | msgstr "Betriebsart" 102 | 103 | msgid "" 104 | "Define the used operating mode for all SAT>IP devices:\n" 105 | "\n" 106 | "off - devices are disabled\n" 107 | "low - devices are working at the lowest priority\n" 108 | "normal - devices are working within normal parameters\n" 109 | "high - devices are working at the highest priority" 110 | msgstr "" 111 | "Bestimme die Betriebsart für alle SAT>IP Geräte:\n" 112 | "\n" 113 | "aus - Geräte sind deaktiviert\n" 114 | "niedrig - Geräte arbeiten mit geringster Priorität\n" 115 | "normal - Geräte arbeiten innerhalb der gewöhnlichen Parameter\n" 116 | "hoch - Geräte arbeiten mit höchster Priorität" 117 | 118 | msgid "Enable CI extension" 119 | msgstr "Aktiviere CI Erweiterung" 120 | 121 | msgid "" 122 | "Define whether a CI extension shall be used.\n" 123 | "\n" 124 | "This setting enables integrated CI/CAM handling found in some SAT>IP hardware (e.g. Digital Devices OctopusNet)." 125 | msgstr "" 126 | "Legt fest ob eine CI Erweiterung genutzt werden soll.\n" 127 | "\n" 128 | "Diese Einstellung aktiviert die Nutzung des integrierten CI/CAM einiger SAT>IP Geräte (z.B. Digital Devices OctopusNet)." 129 | 130 | msgid "CI/CAM" 131 | msgstr "CI/CAM" 132 | 133 | msgid "" 134 | "Define a desired CAM type for the CI slot.\n" 135 | "\n" 136 | "The '---' option lets SAT>IP hardware do the auto-selection." 137 | msgstr "" 138 | "Bestimmt welcher CI Einschub für ein CAM genutzt werden soll.\n" 139 | "\n" 140 | "Die Option '---' überlässt der SAT>IP Hardware die automatische Auswahl." 141 | 142 | msgid "Enable EPG scanning" 143 | msgstr "Aktiviere EPG Aktualisierung" 144 | 145 | msgid "" 146 | "Define whether the EPG background scanning shall be used.\n" 147 | "\n" 148 | "This setting disables the automatic EIT scanning functionality for all SAT>IP devices." 149 | msgstr "" 150 | "Legt fest ob EPG im Hintergrund aktualisiert werden soll oder nicht.\n" 151 | "\n" 152 | "Diese Einstellung schaltet die automatische EIT Aktualisierung für alle SAT>IP Geräte aus." 153 | 154 | msgid "Disabled sources" 155 | msgstr "Deaktivierte Quellen" 156 | 157 | msgid "none" 158 | msgstr "keine" 159 | 160 | msgid "" 161 | "Define number of sources to be disabled.\n" 162 | "\n" 163 | "SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here." 164 | msgstr "" 165 | "Legt die Anzahl der deaktivierten Quellen fest.\n" 166 | "\n" 167 | "Für einige SAT>IP server sind nicht alle Satellitenpositionen verfügbar, nicht verfügbare Quellen können hier ausgeblendet werden" 168 | 169 | msgid "Define a source to be blacklisted." 170 | msgstr "Bestimme eine Quelle, die ausgeblendet wird" 171 | 172 | msgid "Disabled filters" 173 | msgstr "Deaktivierte Filter" 174 | 175 | msgid "" 176 | "Define number of section filters to be disabled.\n" 177 | "\n" 178 | "Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process." 179 | msgstr "" 180 | "Bestimme die Anzahl der Abschnittsfilter die deaktiviert werden sollen.\n" 181 | "\n" 182 | "Bestimmte Abschnittsfilter können unerwünschtes Verhalten mit VDR, z.B. falsche Zeit-Synchronisation, verursachen. Durch das Ausblenden einzelner Filter können nützliche Daten dieser Abschnitte für den VDR erhalten bleiben." 183 | 184 | msgid "Filter" 185 | msgstr "Filter" 186 | 187 | msgid "Define an ill-behaving filter to be blacklisted." 188 | msgstr "Bestimme fehlerhafte Filter die ausgeblendet werden sollen." 189 | 190 | msgid "Transport mode" 191 | msgstr "Übertragungsart" 192 | 193 | msgid "" 194 | "Define which transport mode shall be used.\n" 195 | "\n" 196 | "Unicast, Multicast, RTP-over-TCP" 197 | msgstr "" 198 | "Lege die gewünschte Übertragungsart fest.\n" 199 | "\n" 200 | "Unicast, Multicast, RTP-over-TCP" 201 | 202 | msgid "Enable frontend reuse" 203 | msgstr "Frontend Mehrfachnutzung aktivieren" 204 | 205 | msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled." 206 | msgstr "Festlegung ob ein Tuner-Frontend für mehrere Kanäle genutzt wird." 207 | 208 | msgid "Active SAT>IP servers:" 209 | msgstr "Aktive SAT>IP Server:" 210 | 211 | msgid "Help" 212 | msgstr "Hilfe" 213 | -------------------------------------------------------------------------------- /po/es_ES.po: -------------------------------------------------------------------------------- 1 | # VDR plugin language source file. 2 | # Copyright (C) 2007-2019 Rolf Ahrenberg 3 | # This file is distributed under the same license as the satip package. 4 | # Gabriel Bonich, 2014-2017 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: vdr-satip 2.4.0\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2019-10-27 19:12+0200\n" 11 | "PO-Revision-Date: 2019-10-27 10:27+0200\n" 12 | "Last-Translator: Gabriel Bonich \n" 13 | "Language-Team: Spanish \n" 14 | "Language: es\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | msgid "PAT (0x00)" 20 | msgstr "PAT (0x00)" 21 | 22 | msgid "NIT (0x40)" 23 | msgstr "NIT (0x40)" 24 | 25 | msgid "SDT (0x42)" 26 | msgstr "SDT (0x42)" 27 | 28 | msgid "EIT (0x4E/0x4F/0x5X/0x6X)" 29 | msgstr "EIT (0x4E/0x4F/0x5X/0x6X)" 30 | 31 | msgid "TDT (0x70)" 32 | msgstr "TDT (0x70)" 33 | 34 | msgid "SAT>IP information not available!" 35 | msgstr "SAT>IP Información no disponible!" 36 | 37 | msgid "SAT>IP Devices" 38 | msgstr "SAT>IP Dispositivos" 39 | 40 | msgid "SAT>IP Server" 41 | msgstr "SAT>IP Server" 42 | 43 | msgid "Address" 44 | msgstr "Dirección" 45 | 46 | msgid "Model" 47 | msgstr "Modelo" 48 | 49 | msgid "Description" 50 | msgstr "Descripción" 51 | 52 | msgid "CI extension" 53 | msgstr "Extensión CI" 54 | 55 | msgid "Creation date" 56 | msgstr "Fecha creación" 57 | 58 | msgid "SAT>IP Device Status" 59 | msgstr "SAT>IP Estado del Dispositivo" 60 | 61 | msgid "SAT>IP Information" 62 | msgstr "SAT>IP Información" 63 | 64 | msgid "General" 65 | msgstr "General" 66 | 67 | msgid "Pids" 68 | msgstr "Pids" 69 | 70 | msgid "Filters" 71 | msgstr "Filtros" 72 | 73 | msgid "Bits/bytes" 74 | msgstr "Bits/Bytes" 75 | 76 | msgid "off" 77 | msgstr "Apagado" 78 | 79 | msgid "low" 80 | msgstr "Bajo" 81 | 82 | msgid "normal" 83 | msgstr "Normal" 84 | 85 | msgid "high" 86 | msgstr "Alto" 87 | 88 | msgid "Unicast" 89 | msgstr "Unicast" 90 | 91 | msgid "Multicast" 92 | msgstr "Multicast" 93 | 94 | msgid "RTP-over-TCP" 95 | msgstr "RTP-antes que-TCP" 96 | 97 | msgid "Button$Devices" 98 | msgstr "Dispositivos" 99 | 100 | msgid "Operating mode" 101 | msgstr "Modo de operación" 102 | 103 | msgid "" 104 | "Define the used operating mode for all SAT>IP devices:\n" 105 | "\n" 106 | "off - devices are disabled\n" 107 | "low - devices are working at the lowest priority\n" 108 | "normal - devices are working within normal parameters\n" 109 | "high - devices are working at the highest priority" 110 | msgstr "" 111 | "Define la manera que trabajan los Dispositivos SAT>IP:\n" 112 | "\n" 113 | "Apagat - Dispositivos desactivados\n" 114 | "Baix - Dispositivos trabajando con prioridad Baja\n" 115 | "Normal - Dispositivos trabajando con prioridad Normal\n" 116 | "Alta - Dispositivos trabajando con prioridad Alta" 117 | 118 | msgid "Enable CI extension" 119 | msgstr "Habilitar extensión CI" 120 | 121 | msgid "" 122 | "Define whether a CI extension shall be used.\n" 123 | "\n" 124 | "This setting enables integrated CI/CAM handling found in some SAT>IP hardware (e.g. Digital Devices OctopusNet)." 125 | msgstr "" 126 | "Definir si se utilizará una extensión de CI.\n" 127 | "\n" 128 | "Esto permite la configuración CI/CAM integrado que se encuentra en algunos equipos SAT>IP (ej. Digital Devices OctopusNet)." 129 | 130 | msgid "CI/CAM" 131 | msgstr "CI/CAM" 132 | 133 | msgid "" 134 | "Define a desired CAM type for the CI slot.\n" 135 | "\n" 136 | "The '---' option lets SAT>IP hardware do the auto-selection." 137 | msgstr "" 138 | "Definir el tipo de CAM para la ranura CI.\n" 139 | "\n" 140 | "La opción '---' permite al equipo SAT>IP hacer la selección automática." 141 | 142 | msgid "Enable EPG scanning" 143 | msgstr "Activa Escaneo EPG" 144 | 145 | msgid "" 146 | "Define whether the EPG background scanning shall be used.\n" 147 | "\n" 148 | "This setting disables the automatic EIT scanning functionality for all SAT>IP devices." 149 | msgstr "" 150 | "Definir si se utilitzará el analisí en segundo plano del EPG.\n" 151 | "\n" 152 | "Esta configuración desactiva la funcionalidad del escaneo EIT automática para todos los Dispositivos SAT>IP." 153 | 154 | msgid "Disabled sources" 155 | msgstr "Desactiva fuentes" 156 | 157 | msgid "none" 158 | msgstr "no" 159 | 160 | msgid "" 161 | "Define number of sources to be disabled.\n" 162 | "\n" 163 | "SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here." 164 | msgstr "" 165 | "Definir número de fuentes desactivadas.\n" 166 | "\n" 167 | "SAT>IP servidores que no tenga todas las posiciones de los satélites disponibles y estas se ponen en la lista negra." 168 | 169 | msgid "Define a source to be blacklisted." 170 | msgstr "Define fuentes de la lista negra" 171 | 172 | msgid "Disabled filters" 173 | msgstr "Desactiva filtros" 174 | 175 | msgid "" 176 | "Define number of section filters to be disabled.\n" 177 | "\n" 178 | "Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process." 179 | msgstr "" 180 | "Define el numero de filtros de sección que seran deshabilitados.\n" 181 | "\n" 182 | "Algunos filtros de sección podrian causar un comportamiento no deseado a VDR, como sincronizar mal la hora. Poniendo estos filtros en la lista negra, aqui, la sección de datos útiles se puede dejar intacta para su proceso con el VDR." 183 | 184 | msgid "Filter" 185 | msgstr "Filtra" 186 | 187 | msgid "Define an ill-behaving filter to be blacklisted." 188 | msgstr "Define un filtro para poner en la lista negra." 189 | 190 | msgid "Transport mode" 191 | msgstr "Tipo de Transmisión" 192 | 193 | msgid "" 194 | "Define which transport mode shall be used.\n" 195 | "\n" 196 | "Unicast, Multicast, RTP-over-TCP" 197 | msgstr "" 198 | 199 | msgid "Enable frontend reuse" 200 | msgstr "" 201 | 202 | msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled." 203 | msgstr "" 204 | 205 | msgid "Active SAT>IP servers:" 206 | msgstr "Activa SAT>IP servers:" 207 | 208 | msgid "Help" 209 | msgstr "Ayuda" 210 | -------------------------------------------------------------------------------- /po/fi_FI.po: -------------------------------------------------------------------------------- 1 | # VDR plugin language source file. 2 | # Copyright (C) 2007-2019 Rolf Ahrenberg 3 | # This file is distributed under the same license as the satip package. 4 | # Rolf Ahrenberg, 2015-2019 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: vdr-satip 2.4.0\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2019-10-27 19:12+0200\n" 11 | "PO-Revision-Date: 2019-10-27 10:27+0200\n" 12 | "Last-Translator: Rolf Ahrenberg\n" 13 | "Language-Team: Finnish \n" 14 | "Language: fi\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | msgid "PAT (0x00)" 20 | msgstr "PAT (0x00)" 21 | 22 | msgid "NIT (0x40)" 23 | msgstr "NIT (0x40)" 24 | 25 | msgid "SDT (0x42)" 26 | msgstr "SDT (0x42)" 27 | 28 | msgid "EIT (0x4E/0x4F/0x5X/0x6X)" 29 | msgstr "EIT (0x4E/0x4F/0x5X/0x6X)" 30 | 31 | msgid "TDT (0x70)" 32 | msgstr "TDT (0x70)" 33 | 34 | msgid "SAT>IP information not available!" 35 | msgstr "SAT>IP-tietoja ei saatavilla!" 36 | 37 | msgid "SAT>IP Devices" 38 | msgstr "SAT>IP-laitteet" 39 | 40 | msgid "SAT>IP Server" 41 | msgstr "SAT>IP-palvelin" 42 | 43 | msgid "Address" 44 | msgstr "Osoite" 45 | 46 | msgid "Model" 47 | msgstr "Malli" 48 | 49 | msgid "Description" 50 | msgstr "Kuvaus" 51 | 52 | msgid "CI extension" 53 | msgstr "CI-laajennos" 54 | 55 | msgid "Creation date" 56 | msgstr "Luontiajankohta" 57 | 58 | msgid "SAT>IP Device Status" 59 | msgstr "SAT>IP-laitteiden tiedot" 60 | 61 | msgid "SAT>IP Information" 62 | msgstr "SAT>IP-tiedot" 63 | 64 | msgid "General" 65 | msgstr "Yleiset" 66 | 67 | msgid "Pids" 68 | msgstr "Pidit" 69 | 70 | msgid "Filters" 71 | msgstr "Suodattimet" 72 | 73 | msgid "Bits/bytes" 74 | msgstr "Bitit/tavut" 75 | 76 | msgid "off" 77 | msgstr "ei käytössä" 78 | 79 | msgid "low" 80 | msgstr "matala" 81 | 82 | msgid "normal" 83 | msgstr "normaali" 84 | 85 | msgid "high" 86 | msgstr "korkea" 87 | 88 | msgid "Unicast" 89 | msgstr "Unicast" 90 | 91 | msgid "Multicast" 92 | msgstr "Multicast" 93 | 94 | msgid "RTP-over-TCP" 95 | msgstr "RTP-over-TCP" 96 | 97 | msgid "Button$Devices" 98 | msgstr "Laitteet" 99 | 100 | msgid "Operating mode" 101 | msgstr "Laitteiden toimintatapa" 102 | 103 | msgid "" 104 | "Define the used operating mode for all SAT>IP devices:\n" 105 | "\n" 106 | "off - devices are disabled\n" 107 | "low - devices are working at the lowest priority\n" 108 | "normal - devices are working within normal parameters\n" 109 | "high - devices are working at the highest priority" 110 | msgstr "" 111 | "Määrittele toimintamoodi SAT>IP-laitteille:\n" 112 | "ei käytössä - laitteet ovat pois käytöstä\n" 113 | "matala - laitteet toimivat matalalla prioriteetilla\n" 114 | "normaali - laitteet toimivat normaalilla prioriteetilla\n" 115 | "korkea - laitteet toimivat korkealla prioriteetilla" 116 | 117 | msgid "Enable CI extension" 118 | msgstr "Käytä CI-laajennosta" 119 | 120 | msgid "" 121 | "Define whether a CI extension shall be used.\n" 122 | "\n" 123 | "This setting enables integrated CI/CAM handling found in some SAT>IP hardware (e.g. Digital Devices OctopusNet)." 124 | msgstr "" 125 | "Määrittele CI-laajennoksen käyttöönotto\n" 126 | "\n" 127 | "Tällä asetuksella saadaan otettua käyttöön SAT>IP-laitteiden sisäinen CI-paikka (esim. Digital Devices OctopusNet)." 128 | 129 | msgid "CI/CAM" 130 | msgstr "CI/CAM" 131 | 132 | msgid "" 133 | "Define a desired CAM type for the CI slot.\n" 134 | "\n" 135 | "The '---' option lets SAT>IP hardware do the auto-selection." 136 | msgstr "" 137 | "Määrittele haluttu CAM-tyyppi CI-paikalle.\n" 138 | "\n" 139 | "Vaihtoehto '---' antaa SAT>IP-laitteen valita automaattisesti käytetyn CI-paikan." 140 | 141 | msgid "Enable EPG scanning" 142 | msgstr "Käytä ohjelmaoppaan taustapäivitystä" 143 | 144 | msgid "" 145 | "Define whether the EPG background scanning shall be used.\n" 146 | "\n" 147 | "This setting disables the automatic EIT scanning functionality for all SAT>IP devices." 148 | msgstr "" 149 | "Määrittele ohjelmaoppaan taustapäivityksen olemassaolo.\n" 150 | "\n" 151 | "Tällä asetuksella saadaan otettua automaattinen EIT-datan päivitys pois päältä kaikilta SAT>IP-laitteilta." 152 | 153 | msgid "Disabled sources" 154 | msgstr "Käytöstä poistetut lähteet" 155 | 156 | msgid "none" 157 | msgstr "tyhjä" 158 | 159 | msgid "" 160 | "Define number of sources to be disabled.\n" 161 | "\n" 162 | "SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here." 163 | msgstr "" 164 | "Määrittele käytöstä poistettavien lähteiden lukumäärä.\n" 165 | "\n" 166 | "SAT>IP-palvelimilla ei välttämättä ole kaikkia ohjelmalähteitä tarjolla." 167 | 168 | msgid "Define a source to be blacklisted." 169 | msgstr "Määrittele käytöstä" 170 | 171 | msgid "Disabled filters" 172 | msgstr "Käytöstä poistetut suodattimet" 173 | 174 | msgid "" 175 | "Define number of section filters to be disabled.\n" 176 | "\n" 177 | "Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process." 178 | msgstr "" 179 | "Määrittele käytöstä poistettavien suodattimien lukumäärä sektioille.\n" 180 | "\n" 181 | "Tietyt sektiot saattavat aiheuttaa virheellistä toimintaa VDR:ssä, esimerkiksi asettavat väärän kellonajan, ja näiden poistaminen auttaa VDR:ää toimimaan kunnolla jäljelle jäävien sektioiden kanssa." 182 | 183 | msgid "Filter" 184 | msgstr "Suodatin" 185 | 186 | msgid "Define an ill-behaving filter to be blacklisted." 187 | msgstr "Määrittele käytöstä poistettava suodatin, joka lisätään mustalle listalle." 188 | 189 | msgid "Transport mode" 190 | msgstr "Siirtoyhteystapa" 191 | 192 | msgid "" 193 | "Define which transport mode shall be used.\n" 194 | "\n" 195 | "Unicast, Multicast, RTP-over-TCP" 196 | msgstr "" 197 | "Määrittele käytettävä siirtoyhteystapa.\n" 198 | "\n" 199 | "Unicast, Multicast, RTP-over-TCP" 200 | 201 | msgid "Enable frontend reuse" 202 | msgstr "Uusiokäytä virittimiä" 203 | 204 | msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled." 205 | msgstr "Määrittele virittien uusiokäyttö kanaville, jotka ovat samalla transponderilla." 206 | 207 | msgid "Active SAT>IP servers:" 208 | msgstr "Aktiiviset SAT>IP-palvelimet:" 209 | 210 | msgid "Help" 211 | msgstr "Opaste" 212 | -------------------------------------------------------------------------------- /po/pl_PL.po: -------------------------------------------------------------------------------- 1 | # VDR plugin language source file. 2 | # Copyright (C) 2007-2019 Rolf Ahrenberg 3 | # This file is distributed under the same license as the vdr-satip package. 4 | # Tomasz Maciej Nowak, 2017 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: vdr-satip 2.4.0\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2019-10-27 19:12+0200\n" 11 | "PO-Revision-Date: 2019-10-27 10:27+0200\n" 12 | "Last-Translator: Tomasz Maciej Nowak \n" 13 | "Language-Team: Polish \n" 14 | "Language: pl_PL\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "X-Generator: Poedit 1.8.11\n" 19 | 20 | msgid "PAT (0x00)" 21 | msgstr "PAT (0x00)" 22 | 23 | msgid "NIT (0x40)" 24 | msgstr "NIT (0x40)" 25 | 26 | msgid "SDT (0x42)" 27 | msgstr "SDT (0x42)" 28 | 29 | msgid "EIT (0x4E/0x4F/0x5X/0x6X)" 30 | msgstr "EIT (0x4E/0x4F/0x5X/0x6X)" 31 | 32 | msgid "TDT (0x70)" 33 | msgstr "TDT (0x70)" 34 | 35 | msgid "SAT>IP information not available!" 36 | msgstr "Informacja o SAT>IP niedostępna!" 37 | 38 | msgid "SAT>IP Devices" 39 | msgstr "Urządzenia SAT>IP" 40 | 41 | msgid "SAT>IP Server" 42 | msgstr "Serwer SAT>IP" 43 | 44 | msgid "Address" 45 | msgstr "Adres" 46 | 47 | msgid "Model" 48 | msgstr "Model" 49 | 50 | msgid "Description" 51 | msgstr "Opis" 52 | 53 | msgid "CI extension" 54 | msgstr "Rozszerzenie CI" 55 | 56 | msgid "Creation date" 57 | msgstr "Data produkcji" 58 | 59 | msgid "SAT>IP Device Status" 60 | msgstr "Status urządzenia SAT>IP" 61 | 62 | msgid "SAT>IP Information" 63 | msgstr "SAT>IP - informacje" 64 | 65 | msgid "General" 66 | msgstr "Główne" 67 | 68 | msgid "Pids" 69 | msgstr "Pidy" 70 | 71 | msgid "Filters" 72 | msgstr "Filtry" 73 | 74 | msgid "Bits/bytes" 75 | msgstr "Bity/bajty" 76 | 77 | msgid "off" 78 | msgstr "wyłączone" 79 | 80 | msgid "low" 81 | msgstr "niski" 82 | 83 | msgid "normal" 84 | msgstr "normalny" 85 | 86 | msgid "high" 87 | msgstr "wysoki" 88 | 89 | msgid "Unicast" 90 | msgstr "Unicast" 91 | 92 | msgid "Multicast" 93 | msgstr "Multicast" 94 | 95 | msgid "RTP-over-TCP" 96 | msgstr "RTP-over-TCP" 97 | 98 | msgid "Button$Devices" 99 | msgstr "Urządzenia" 100 | 101 | msgid "Operating mode" 102 | msgstr "Tryb pracy" 103 | 104 | msgid "" 105 | "Define the used operating mode for all SAT>IP devices:\n" 106 | "\n" 107 | "off - devices are disabled\n" 108 | "low - devices are working at the lowest priority\n" 109 | "normal - devices are working within normal parameters\n" 110 | "high - devices are working at the highest priority" 111 | msgstr "" 112 | "Określa tryb pracy wszystkich urządzeń SAT>IP:\n" 113 | "\n" 114 | "wyłączone - urządzenia są wyłączone\n" 115 | "niski - urządzenia pracują z najniższym priorytetem\n" 116 | "normalny - urządzenia pracują z normalnymi parametrami\n" 117 | "wysoki - urządzenia pracują z najwyższym priorytetem" 118 | 119 | msgid "Enable CI extension" 120 | msgstr "Włącz rozszerzenie CI" 121 | 122 | msgid "" 123 | "Define whether a CI extension shall be used.\n" 124 | "\n" 125 | "This setting enables integrated CI/CAM handling found in some SAT>IP hardware (e.g. Digital Devices OctopusNet)." 126 | msgstr "" 127 | "Określa czy korzystać z rozszerzenia CI.\n" 128 | "\n" 129 | "To ustawienie włącza obsługę dostępnego czytnika CI/CAM w niektórych urządzeniach SAT>IP (np. Digital Devices OctopusNet)." 130 | 131 | msgid "CI/CAM" 132 | msgstr "CI/CAM" 133 | 134 | msgid "" 135 | "Define a desired CAM type for the CI slot.\n" 136 | "\n" 137 | "The '---' option lets SAT>IP hardware do the auto-selection." 138 | msgstr "" 139 | "Określa typ modułu CAM w czytniku CI.\n" 140 | "\n" 141 | "Opcja '---' pozwala urządzeniu SAT>IP automatycznie wybrać typ." 142 | 143 | msgid "Enable EPG scanning" 144 | msgstr "Włącz skanowanie EPG" 145 | 146 | msgid "" 147 | "Define whether the EPG background scanning shall be used.\n" 148 | "\n" 149 | "This setting disables the automatic EIT scanning functionality for all SAT>IP devices." 150 | msgstr "" 151 | "Określa czy przeprowadzać skanowanie EPG w tle.\n" 152 | "\n" 153 | "To ustawienie wyłącza funkcję automatycznego skanowania EIT dla wszystkich urządzeń SAT>IP." 154 | 155 | msgid "Disabled sources" 156 | msgstr "Wyłączone źródła" 157 | 158 | msgid "none" 159 | msgstr "brak" 160 | 161 | msgid "" 162 | "Define number of sources to be disabled.\n" 163 | "\n" 164 | "SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here." 165 | msgstr "" 166 | "Określa liczbę wyłączonych źródeł.\n" 167 | "\n" 168 | "Serwery SAT>IP mogą nie mieć dostępu do niektórych pozycji satelitarnych, więc tutaj można je wyłączyć." 169 | 170 | msgid "Define a source to be blacklisted." 171 | msgstr "Określ źródła do wyłączenia." 172 | 173 | msgid "Disabled filters" 174 | msgstr "Wyłączone filtry" 175 | 176 | msgid "" 177 | "Define number of section filters to be disabled.\n" 178 | "\n" 179 | "Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process." 180 | msgstr "" 181 | "Określa liczbę wyłączonych filtrów sekcji.\n" 182 | "\n" 183 | "Niektóre filtry sekcji mogą powodować niezamierzone efekty w VDR, takie jak zły czas synchronizacji. Poprzez wyłączenie niektórych filtrów, użyteczne dane sekcji będą dostępne do przetworzenia dla VDR." 184 | 185 | msgid "Filter" 186 | msgstr "Filtr" 187 | 188 | msgid "Define an ill-behaving filter to be blacklisted." 189 | msgstr "Określa filtry powodujące zakłócenia, które mają być wyłączone." 190 | 191 | msgid "Transport mode" 192 | msgstr "Tryb" 193 | 194 | msgid "" 195 | "Define which transport mode shall be used.\n" 196 | "\n" 197 | "Unicast, Multicast, RTP-over-TCP" 198 | msgstr "" 199 | "Określa tryb transmisji.\n" 200 | "Unicast, Multicast, RTP-over-TCP." 201 | 202 | msgid "Enable frontend reuse" 203 | msgstr "" 204 | 205 | msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled." 206 | msgstr "" 207 | 208 | msgid "Active SAT>IP servers:" 209 | msgstr "Aktywne serwery SAT>IP:" 210 | 211 | msgid "Help" 212 | msgstr "Pomoc" 213 | -------------------------------------------------------------------------------- /poller.c: -------------------------------------------------------------------------------- 1 | /* 2 | * poller.c: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #define __STDC_FORMAT_MACROS // Required for format specifiers 9 | #include 10 | #include 11 | 12 | #include "config.h" 13 | #include "common.h" 14 | #include "log.h" 15 | #include "poller.h" 16 | 17 | cSatipPoller *cSatipPoller::instanceS = NULL; 18 | 19 | cSatipPoller *cSatipPoller::GetInstance(void) 20 | { 21 | if (!instanceS) 22 | instanceS = new cSatipPoller(); 23 | return instanceS; 24 | } 25 | 26 | bool cSatipPoller::Initialize(void) 27 | { 28 | debug1("%s", __PRETTY_FUNCTION__); 29 | if (instanceS) 30 | instanceS->Activate(); 31 | return true; 32 | } 33 | 34 | void cSatipPoller::Destroy(void) 35 | { 36 | debug1("%s", __PRETTY_FUNCTION__); 37 | if (instanceS) 38 | instanceS->Deactivate(); 39 | } 40 | 41 | cSatipPoller::cSatipPoller() 42 | : cThread("SATIP poller"), 43 | mutexM(), 44 | fdM(epoll_create(eMaxFileDescriptors)) 45 | { 46 | debug1("%s", __PRETTY_FUNCTION__); 47 | } 48 | 49 | cSatipPoller::~cSatipPoller() 50 | { 51 | debug1("%s", __PRETTY_FUNCTION__); 52 | Deactivate(); 53 | cMutexLock MutexLock(&mutexM); 54 | close(fdM); 55 | // Free allocated memory 56 | } 57 | 58 | void cSatipPoller::Activate(void) 59 | { 60 | // Start the thread 61 | Start(); 62 | } 63 | 64 | void cSatipPoller::Deactivate(void) 65 | { 66 | debug1("%s", __PRETTY_FUNCTION__); 67 | cMutexLock MutexLock(&mutexM); 68 | if (Running()) 69 | Cancel(3); 70 | } 71 | 72 | void cSatipPoller::Action(void) 73 | { 74 | debug1("%s Entering", __PRETTY_FUNCTION__); 75 | struct epoll_event events[eMaxFileDescriptors]; 76 | uint64_t maxElapsed = 0; 77 | // Increase priority 78 | SetPriority(-1); 79 | // Do the thread loop 80 | while (Running()) { 81 | int nfds = epoll_wait(fdM, events, eMaxFileDescriptors, -1); 82 | ERROR_IF_FUNC((nfds == -1 && errno != EINTR), "epoll_wait() failed", break, ;); 83 | for (int i = 0; i < nfds; ++i) { 84 | cSatipPollerIf* poll = reinterpret_cast(events[i].data.ptr); 85 | if (poll) { 86 | uint64_t elapsed; 87 | cTimeMs processing(0); 88 | poll->Process(); 89 | elapsed = processing.Elapsed(); 90 | if (elapsed > maxElapsed) { 91 | maxElapsed = elapsed; 92 | debug1("%s Processing %s took %" PRIu64 " ms", __PRETTY_FUNCTION__, *(poll->ToString()), maxElapsed); 93 | } 94 | } 95 | } 96 | } 97 | debug1("%s Exiting", __PRETTY_FUNCTION__); 98 | } 99 | 100 | bool cSatipPoller::Register(cSatipPollerIf &pollerP) 101 | { 102 | debug1("%s fd=%d", __PRETTY_FUNCTION__, pollerP.GetFd()); 103 | cMutexLock MutexLock(&mutexM); 104 | 105 | struct epoll_event ev; 106 | ev.events = EPOLLIN | EPOLLET; 107 | ev.data.ptr = &pollerP; 108 | ERROR_IF_RET(epoll_ctl(fdM, EPOLL_CTL_ADD, pollerP.GetFd(), &ev) == -1, "epoll_ctl(EPOLL_CTL_ADD) failed", return false); 109 | debug1("%s Added interface fd=%d", __PRETTY_FUNCTION__, pollerP.GetFd()); 110 | 111 | return true; 112 | } 113 | 114 | bool cSatipPoller::Unregister(cSatipPollerIf &pollerP) 115 | { 116 | debug1("%s fd=%d", __PRETTY_FUNCTION__, pollerP.GetFd()); 117 | cMutexLock MutexLock(&mutexM); 118 | ERROR_IF_RET((epoll_ctl(fdM, EPOLL_CTL_DEL, pollerP.GetFd(), NULL) == -1), "epoll_ctl(EPOLL_CTL_DEL) failed", return false); 119 | debug1("%s Removed interface fd=%d", __PRETTY_FUNCTION__, pollerP.GetFd()); 120 | 121 | return true; 122 | } 123 | -------------------------------------------------------------------------------- /poller.h: -------------------------------------------------------------------------------- 1 | /* 2 | * poller.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_POLLER_H 9 | #define __SATIP_POLLER_H 10 | 11 | #include 12 | #include 13 | 14 | #include "pollerif.h" 15 | 16 | class cSatipPoller : public cThread { 17 | private: 18 | enum { 19 | eMaxFileDescriptors = SATIP_MAX_DEVICES * 2, // Data + Application 20 | }; 21 | static cSatipPoller *instanceS; 22 | cMutex mutexM; 23 | int fdM; 24 | void Activate(void); 25 | void Deactivate(void); 26 | // constructor 27 | cSatipPoller(); 28 | // to prevent copy constructor and assignment 29 | cSatipPoller(const cSatipPoller&); 30 | cSatipPoller& operator=(const cSatipPoller&); 31 | 32 | protected: 33 | virtual void Action(void); 34 | 35 | public: 36 | static cSatipPoller *GetInstance(void); 37 | static bool Initialize(void); 38 | static void Destroy(void); 39 | virtual ~cSatipPoller(); 40 | bool Register(cSatipPollerIf &pollerP); 41 | bool Unregister(cSatipPollerIf &pollerP); 42 | }; 43 | 44 | #endif // __SATIP_POLLER_H 45 | -------------------------------------------------------------------------------- /pollerif.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pollerif.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_POLLERIF_H 9 | #define __SATIP_POLLERIF_H 10 | 11 | class cSatipPollerIf { 12 | public: 13 | cSatipPollerIf() {} 14 | virtual ~cSatipPollerIf() {} 15 | virtual int GetFd(void) = 0; 16 | virtual void Process(void) = 0; 17 | virtual void Process(unsigned char *dataP, int lengthP) = 0; 18 | virtual cString ToString(void) const = 0; 19 | 20 | private: 21 | explicit cSatipPollerIf(const cSatipPollerIf&); 22 | cSatipPollerIf& operator=(const cSatipPollerIf&); 23 | }; 24 | 25 | #endif // __SATIP_POLLERIF_H 26 | -------------------------------------------------------------------------------- /rtcp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rtcp.c: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #include "config.h" 9 | #include "common.h" 10 | #include "log.h" 11 | #include "rtcp.h" 12 | 13 | cSatipRtcp::cSatipRtcp(cSatipTunerIf &tunerP) 14 | : tunerM(tunerP), 15 | bufferLenM(eApplicationMaxSizeB), 16 | bufferM(MALLOC(unsigned char, bufferLenM)) 17 | { 18 | debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); 19 | if (bufferM) 20 | memset(bufferM, 0, bufferLenM); 21 | else 22 | error("Cannot create RTCP buffer! [device %d]", tunerM.GetId()); 23 | } 24 | 25 | cSatipRtcp::~cSatipRtcp() 26 | { 27 | debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); 28 | FREE_POINTER(bufferM); 29 | } 30 | 31 | int cSatipRtcp::GetFd(void) 32 | { 33 | debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); 34 | return Fd(); 35 | } 36 | 37 | int cSatipRtcp::GetApplicationOffset(unsigned char *bufferP, int *lengthP) 38 | { 39 | debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP ? *lengthP : -1, tunerM.GetId()); 40 | if (!lengthP) 41 | return -1; 42 | int offset = 0; 43 | int total = *lengthP; 44 | while (total > 0) { 45 | // Version 46 | unsigned int v = (bufferP[offset] >> 6) & 0x03; 47 | // Padding 48 | //unsigned int p = (bufferP[offset] >> 5) & 0x01; 49 | // Subtype 50 | //unsigned int st = bufferP[offset] & 0x1F; 51 | // Payload type 52 | unsigned int pt = bufferP[offset + 1] & 0xFF; 53 | // Length 54 | unsigned int length = ((bufferP[offset + 2] & 0xFF) << 8) | (bufferP[offset + 3] & 0xFF); 55 | // Convert it to bytes 56 | length = (length + 1) * 4; 57 | // V=2, APP = 204 58 | if ((v == 2) && (pt == 204)) { 59 | // SSCR/CSCR 60 | //unsigned int ssrc = ((bufferP[offset + 4] & 0xFF) << 24) | ((bufferP[offset + 5] & 0xFF) << 16) | 61 | // ((bufferP[offset + 6] & 0xFF) << 8) | (bufferP[offset + 7] & 0xFF); 62 | // Name 63 | if ((bufferP[offset + 8] == 'S') && (bufferP[offset + 9] == 'E') && 64 | (bufferP[offset + 10] == 'S') && (bufferP[offset + 11] == '1')) { 65 | // Identifier 66 | //unsigned int id = ((bufferP[offset + 12] & 0xFF) << 8) | (bufferP[offset + 13] & 0xFF); 67 | // String length 68 | int string_length = ((bufferP[offset + 14] & 0xFF) << 8) | (bufferP[offset + 15] & 0xFF); 69 | if (string_length > 0) { 70 | *lengthP = string_length; 71 | return (offset + 16); 72 | } 73 | } 74 | } 75 | offset += length; 76 | total -= length; 77 | } 78 | *lengthP = 0; 79 | return -1; 80 | } 81 | 82 | void cSatipRtcp::Process(void) 83 | { 84 | debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); 85 | if (bufferM) { 86 | int length; 87 | while ((length = Read(bufferM, bufferLenM)) > 0) { 88 | int offset = GetApplicationOffset(bufferM, &length); 89 | if (offset >= 0) 90 | tunerM.ProcessApplicationData(bufferM + offset, length); 91 | } 92 | } 93 | } 94 | 95 | void cSatipRtcp::Process(unsigned char *dataP, int lengthP) 96 | { 97 | debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); 98 | if (dataP && lengthP > 0) { 99 | int offset = GetApplicationOffset(dataP, &lengthP); 100 | if (offset >= 0) 101 | tunerM.ProcessApplicationData(dataP + offset, lengthP); 102 | } 103 | } 104 | 105 | cString cSatipRtcp::ToString(void) const 106 | { 107 | return cString::sprintf("RTCP [device %d]", tunerM.GetId()); 108 | } 109 | -------------------------------------------------------------------------------- /rtcp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rtcp.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_RTCP_H_ 9 | #define __SATIP_RTCP_H_ 10 | 11 | #include "socket.h" 12 | #include "tunerif.h" 13 | #include "pollerif.h" 14 | 15 | class cSatipRtcp : public cSatipSocket, public cSatipPollerIf { 16 | private: 17 | enum { 18 | eApplicationMaxSizeB = 1500, 19 | }; 20 | cSatipTunerIf &tunerM; 21 | unsigned int bufferLenM; 22 | unsigned char *bufferM; 23 | int GetApplicationOffset(unsigned char *bufferP, int *lengthP); 24 | 25 | public: 26 | explicit cSatipRtcp(cSatipTunerIf &tunerP); 27 | virtual ~cSatipRtcp(); 28 | 29 | // for internal poller interface 30 | public: 31 | virtual int GetFd(void); 32 | virtual void Process(void); 33 | virtual void Process(unsigned char *dataP, int lengthP); 34 | virtual cString ToString(void) const; 35 | }; 36 | 37 | #endif /* __SATIP_RTCP_H_ */ 38 | -------------------------------------------------------------------------------- /rtp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rtp.c: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #define __STDC_FORMAT_MACROS // Required for format specifiers 9 | #include 10 | 11 | #include "config.h" 12 | #include "common.h" 13 | #include "log.h" 14 | #include "rtp.h" 15 | 16 | cSatipRtp::cSatipRtp(cSatipTunerIf &tunerP) 17 | : cSatipSocket(SatipConfig.GetRtpRcvBufSize()), 18 | tunerM(tunerP), 19 | bufferLenM(eRtpPacketReadCount * eMaxUdpPacketSizeB), 20 | bufferM(MALLOC(unsigned char, bufferLenM)), 21 | lastErrorReportM(0), 22 | packetErrorsM(0), 23 | sequenceNumberM(-1) 24 | { 25 | debug1("%s () [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); 26 | if (!bufferM) 27 | error("Cannot create RTP buffer! [device %d]", tunerM.GetId()); 28 | } 29 | 30 | cSatipRtp::~cSatipRtp() 31 | { 32 | debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); 33 | FREE_POINTER(bufferM); 34 | } 35 | 36 | int cSatipRtp::GetFd(void) 37 | { 38 | return Fd(); 39 | } 40 | 41 | void cSatipRtp::Close(void) 42 | { 43 | debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); 44 | 45 | cSatipSocket::Close(); 46 | 47 | sequenceNumberM = -1; 48 | if (packetErrorsM) { 49 | info("Detected %d RTP packet error%s [device %d]", packetErrorsM, packetErrorsM == 1 ? "": "s", tunerM.GetId()); 50 | packetErrorsM = 0; 51 | lastErrorReportM = time(NULL); 52 | } 53 | } 54 | 55 | int cSatipRtp::GetHeaderLength(unsigned char *bufferP, unsigned int lengthP) 56 | { 57 | debug16("%s (, %d) [device %d]", __PRETTY_FUNCTION__, lengthP, tunerM.GetId()); 58 | unsigned int headerlen = 0; 59 | 60 | if (lengthP > 0) { 61 | if (bufferP[0] == TS_SYNC_BYTE) 62 | return headerlen; 63 | else if (lengthP > 3) { 64 | // http://tools.ietf.org/html/rfc3550 65 | // http://tools.ietf.org/html/rfc2250 66 | // Version 67 | unsigned int v = (bufferP[0] >> 6) & 0x03; 68 | // Extension bit 69 | unsigned int x = (bufferP[0] >> 4) & 0x01; 70 | // CSCR count 71 | unsigned int cc = bufferP[0] & 0x0F; 72 | // Payload type: MPEG2 TS = 33 73 | unsigned int pt = bufferP[1] & 0x7F; 74 | if (pt != 33) 75 | debug7("%s (%d) Received invalid RTP payload type %d - v=%d [device %d]", 76 | __PRETTY_FUNCTION__, lengthP, pt, v, tunerM.GetId()); 77 | // Sequence number 78 | int seq = ((bufferP[2] & 0xFF) << 8) | (bufferP[3] & 0xFF); 79 | if ((((sequenceNumberM + 1) % 0xFFFF) == 0) && (seq == 0xFFFF)) 80 | sequenceNumberM = -1; 81 | else if ((sequenceNumberM >= 0) && (((sequenceNumberM + 1) % 0xFFFF) != seq)) { 82 | packetErrorsM++; 83 | if (time(NULL) - lastErrorReportM > eReportIntervalS) { 84 | info("Detected %d RTP packet error%s [device %d]", packetErrorsM, packetErrorsM == 1 ? "": "s", tunerM.GetId()); 85 | packetErrorsM = 0; 86 | lastErrorReportM = time(NULL); 87 | } 88 | sequenceNumberM = seq; 89 | } 90 | else 91 | sequenceNumberM = seq; 92 | // Header length 93 | headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t); 94 | // Check if extension 95 | if (x) { 96 | // Extension header length 97 | unsigned int ehl = (((bufferP[headerlen + 2] & 0xFF) << 8) | (bufferP[headerlen + 3] & 0xFF)); 98 | // Update header length 99 | headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t); 100 | } 101 | // Check for empty payload 102 | if (lengthP == headerlen) { 103 | debug7("%s (%d) Received empty RTP packet #%d [device %d]", __PRETTY_FUNCTION__, lengthP, seq, tunerM.GetId()); 104 | headerlen = -1; 105 | } 106 | // Check that rtp is version 2 and payload contains multiple of TS packet data 107 | else if ((v != 2) || (((lengthP - headerlen) % TS_SIZE) != 0) || (bufferP[headerlen] != TS_SYNC_BYTE)) { 108 | debug7("%s (%d) Received incorrect RTP packet #%d v=%d len=%d sync=0x%02X [device %d]", __PRETTY_FUNCTION__, 109 | lengthP, seq, v, headerlen, bufferP[headerlen], tunerM.GetId()); 110 | headerlen = -1; 111 | } 112 | else 113 | debug7("%s (%d) Received RTP packet #%d v=%d len=%d sync=0x%02X [device %d]", __PRETTY_FUNCTION__, 114 | lengthP, seq, v, headerlen, bufferP[headerlen], tunerM.GetId()); 115 | } 116 | } 117 | 118 | return headerlen; 119 | } 120 | 121 | void cSatipRtp::Process(void) 122 | { 123 | debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); 124 | if (bufferM) { 125 | unsigned int lenMsg[eRtpPacketReadCount]; 126 | uint64_t elapsed; 127 | int count = 0; 128 | cTimeMs processing(0); 129 | 130 | do { 131 | count = ReadMulti(bufferM, lenMsg, eRtpPacketReadCount, eMaxUdpPacketSizeB); 132 | for (int i = 0; i < count; ++i) { 133 | unsigned char *p = &bufferM[i * eMaxUdpPacketSizeB]; 134 | int headerlen = GetHeaderLength(p, lenMsg[i]); 135 | if ((headerlen >= 0) && (headerlen < (int)lenMsg[i])) 136 | tunerM.ProcessVideoData(p + headerlen, lenMsg[i] - headerlen); 137 | } 138 | } while (count >= eRtpPacketReadCount); 139 | 140 | elapsed = processing.Elapsed(); 141 | if (elapsed > 1) 142 | debug6("%s %d read(s) took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, count, elapsed, tunerM.GetId()); 143 | } 144 | } 145 | 146 | void cSatipRtp::Process(unsigned char *dataP, int lengthP) 147 | { 148 | debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); 149 | if (dataP && lengthP > 0) { 150 | uint64_t elapsed; 151 | cTimeMs processing(0); 152 | int headerlen = GetHeaderLength(dataP, lengthP); 153 | if ((headerlen >= 0) && (headerlen < lengthP)) 154 | tunerM.ProcessVideoData(dataP + headerlen, lengthP - headerlen); 155 | 156 | elapsed = processing.Elapsed(); 157 | if (elapsed > 1) 158 | debug6("%s %d read(s) took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, lengthP, elapsed, tunerM.GetId()); 159 | } 160 | } 161 | 162 | cString cSatipRtp::ToString(void) const 163 | { 164 | return cString::sprintf("RTP [device %d]", tunerM.GetId()); 165 | } 166 | -------------------------------------------------------------------------------- /rtp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rtp.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_RTP_H_ 9 | #define __SATIP_RTP_H_ 10 | 11 | #include "socket.h" 12 | #include "tunerif.h" 13 | #include "pollerif.h" 14 | 15 | class cSatipRtp : public cSatipSocket, public cSatipPollerIf { 16 | private: 17 | enum { 18 | eRtpPacketReadCount = 50, 19 | eMaxUdpPacketSizeB = TS_SIZE * 7 + 12, 20 | eReportIntervalS = 300 // in seconds 21 | }; 22 | cSatipTunerIf &tunerM; 23 | unsigned int bufferLenM; 24 | unsigned char *bufferM; 25 | time_t lastErrorReportM; 26 | int packetErrorsM; 27 | int sequenceNumberM; 28 | int GetHeaderLength(unsigned char *bufferP, unsigned int lengthP); 29 | 30 | public: 31 | explicit cSatipRtp(cSatipTunerIf &tunerP); 32 | virtual ~cSatipRtp(); 33 | virtual void Close(void); 34 | 35 | // for internal poller interface 36 | public: 37 | virtual int GetFd(void); 38 | virtual void Process(void); 39 | virtual void Process(unsigned char *dataP, int lengthP); 40 | virtual cString ToString(void) const; 41 | }; 42 | 43 | #endif /* __SATIP_RTP_H_ */ 44 | -------------------------------------------------------------------------------- /rtsp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rtsp.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_RTSP_H 9 | #define __SATIP_RTSP_H 10 | 11 | #include 12 | #include 13 | 14 | #ifndef CURLOPT_RTSPHEADER 15 | #error "libcurl is missing required RTSP support" 16 | #endif 17 | 18 | #include "common.h" 19 | #include "tunerif.h" 20 | 21 | class cSatipRtsp { 22 | private: 23 | static size_t HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP); 24 | static size_t DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP); 25 | static size_t InterleaveCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP); 26 | static int DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP); 27 | 28 | enum { 29 | eConnectTimeoutMs = 1500, // in milliseconds 30 | }; 31 | 32 | cSatipTunerIf &tunerM; 33 | cSatipMemoryBuffer headerBufferM; 34 | cSatipMemoryBuffer dataBufferM; 35 | CURL *handleM; 36 | struct curl_slist *headerListM; 37 | cString errorNoMoreM; 38 | cString errorOutOfRangeM; 39 | cString errorCheckSyntaxM; 40 | int modeM; 41 | unsigned int interleavedRtpIdM; 42 | unsigned int interleavedRtcpIdM; 43 | 44 | void Create(void); 45 | void Destroy(void); 46 | void ParseHeader(void); 47 | void ParseData(void); 48 | bool ValidateLatestResponse(long *rcP); 49 | 50 | // to prevent copy constructor and assignment 51 | cSatipRtsp(const cSatipRtsp&); 52 | cSatipRtsp& operator=(const cSatipRtsp&); 53 | 54 | public: 55 | explicit cSatipRtsp(cSatipTunerIf &tunerP); 56 | virtual ~cSatipRtsp(); 57 | 58 | cString GetActiveMode(void); 59 | cString RtspUnescapeString(const char *strP); 60 | void Reset(void); 61 | bool SetInterface(const char *bindAddrP); 62 | bool Receive(const char *uriP); 63 | bool Options(const char *uriP); 64 | bool Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTcpP); 65 | bool SetSession(const char *sessionP); 66 | bool Describe(const char *uriP); 67 | bool Play(const char *uriP); 68 | bool Teardown(const char *uriP); 69 | }; 70 | 71 | #endif // __SATIP_RTSP_H 72 | -------------------------------------------------------------------------------- /sectionfilter.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sectionfilter.c: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #include "config.h" 9 | #include "log.h" 10 | #include "sectionfilter.h" 11 | 12 | cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP) 13 | : pusiSeenM(0), 14 | feedCcM(0), 15 | doneqM(0), 16 | secBufM(NULL), 17 | secBufpM(0), 18 | secLenM(0), 19 | tsFeedpM(0), 20 | pidM(pidP), 21 | tidM(tidP), 22 | maskM(maskP), 23 | ringBufferM(new cRingBufferFrame(eDmxMaxSectionCount * eDmxMaxSectionSize)), 24 | deviceIndexM(deviceIndexP) 25 | { 26 | debug16("%s (%d, %d, %d, %d) [device %d]", __PRETTY_FUNCTION__, deviceIndexM, pidM, tidP, maskP, deviceIndexM); 27 | 28 | memset(secBufBaseM, 0, sizeof(secBufBaseM)); 29 | 30 | // Create sockets 31 | socketM[0] = socketM[1] = -1; 32 | if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, socketM) != 0) { 33 | char tmp[64]; 34 | error("Opening section filter sockets failed (device=%d pid=%d): %s", deviceIndexM, pidM, strerror_r(errno, tmp, sizeof(tmp))); 35 | } 36 | else if ((fcntl(socketM[0], F_SETFL, O_NONBLOCK) != 0) || (fcntl(socketM[1], F_SETFL, O_NONBLOCK) != 0)) { 37 | char tmp[64]; 38 | error("Setting section filter socket to non-blocking mode failed (device=%d pid=%d): %s", deviceIndexM, pidM, strerror_r(errno, tmp, sizeof(tmp))); 39 | } 40 | } 41 | 42 | cSatipSectionFilter::~cSatipSectionFilter() 43 | { 44 | debug16("%s pid=%d [device %d]", __PRETTY_FUNCTION__, pidM, deviceIndexM); 45 | int tmp = socketM[1]; 46 | socketM[1] = -1; 47 | if (tmp >= 0) 48 | close(tmp); 49 | tmp = socketM[0]; 50 | socketM[0] = -1; 51 | if (tmp >= 0) 52 | close(tmp); 53 | secBufM = NULL; 54 | DELETENULL(ringBufferM); 55 | } 56 | 57 | inline uint16_t cSatipSectionFilter::GetLength(const uint8_t *dataP) 58 | { 59 | return (uint16_t)(3 + ((dataP[1] & 0x0f) << 8) + dataP[2]); 60 | } 61 | 62 | void cSatipSectionFilter::New(void) 63 | { 64 | tsFeedpM = secBufpM = secLenM = 0; 65 | secBufM = secBufBaseM; 66 | } 67 | 68 | int cSatipSectionFilter::Filter(void) 69 | { 70 | if (secBufM) { 71 | if ((tidM & maskM) == (secBufM[0] & maskM)) { 72 | if (ringBufferM && (secLenM > 0)) { 73 | cFrame* section = new cFrame(secBufM, secLenM); 74 | if (!ringBufferM->Put(section)) 75 | DELETE_POINTER(section); 76 | } 77 | } 78 | } 79 | return 0; 80 | } 81 | 82 | inline int cSatipSectionFilter::Feed(void) 83 | { 84 | if (Filter() < 0) 85 | return -1; 86 | secLenM = 0; 87 | return 0; 88 | } 89 | 90 | int cSatipSectionFilter::CopyDump(const uint8_t *bufP, uint8_t lenP) 91 | { 92 | uint16_t limit, n; 93 | 94 | if (tsFeedpM >= eDmxMaxSectionFeedSize) 95 | return 0; 96 | 97 | if (tsFeedpM + lenP > eDmxMaxSectionFeedSize) 98 | lenP = (uint8_t)(eDmxMaxSectionFeedSize - tsFeedpM); 99 | 100 | if (lenP == 0) 101 | return 0; 102 | 103 | memcpy(secBufBaseM + tsFeedpM, bufP, lenP); 104 | tsFeedpM = uint16_t(tsFeedpM + lenP); 105 | 106 | limit = tsFeedpM; 107 | if (limit > eDmxMaxSectionFeedSize) 108 | return -1; // internal error should never happen 109 | 110 | // Always set secbuf 111 | secBufM = secBufBaseM + secBufpM; 112 | 113 | for (n = 0; secBufpM + 2 < limit; ++n) { 114 | uint16_t seclen = GetLength(secBufM); 115 | if ((seclen > eDmxMaxSectionSize) || ((seclen + secBufpM) > limit)) 116 | return 0; 117 | secLenM = seclen; 118 | if (pusiSeenM) 119 | Feed(); 120 | secBufpM = uint16_t(secBufpM + seclen); 121 | secBufM += seclen; 122 | } 123 | return 0; 124 | } 125 | 126 | void cSatipSectionFilter::Process(const uint8_t* dataP) 127 | { 128 | if (dataP[0] != TS_SYNC_BYTE) 129 | return; 130 | 131 | // Stop if not the PID this filter is looking for 132 | if (ts_pid(dataP) != pidM) 133 | return; 134 | 135 | uint8_t count = payload(dataP); 136 | 137 | // Check if no payload or out of range 138 | if (count == 0) 139 | return; 140 | 141 | // Payload start 142 | uint8_t p = (uint8_t)(TS_SIZE - count); 143 | 144 | uint8_t cc = (uint8_t)(dataP[3] & 0x0f); 145 | int ccok = ((feedCcM + 1) & 0x0f) == cc; 146 | feedCcM = cc; 147 | 148 | int dc_i = 0; 149 | if (dataP[3] & 0x20) { 150 | // Adaption field present, check for discontinuity_indicator 151 | if ((dataP[4] > 0) && (dataP[5] & 0x80)) 152 | dc_i = 1; 153 | } 154 | 155 | if (!ccok || dc_i) { 156 | // Discontinuity detected. Reset pusiSeenM = 0 to 157 | // stop feeding of suspicious data until next PUSI=1 arrives 158 | pusiSeenM = 0; 159 | New(); 160 | } 161 | 162 | if (dataP[1] & 0x40) { 163 | // PUSI=1 (is set), section boundary is here 164 | if (count > 1 && dataP[p] < count) { 165 | const uint8_t *before = &dataP[p + 1]; 166 | uint8_t before_len = dataP[p]; 167 | const uint8_t *after = &before[before_len]; 168 | uint8_t after_len = (uint8_t)(count - 1 - before_len); 169 | CopyDump(before, before_len); 170 | 171 | // Before start of new section, set pusiSeenM = 1 172 | pusiSeenM = 1; 173 | New(); 174 | CopyDump(after, after_len); 175 | } 176 | } 177 | else { 178 | // PUSI=0 (is not set), no section boundary 179 | CopyDump(&dataP[p], count); 180 | } 181 | } 182 | 183 | void cSatipSectionFilter::Send(void) 184 | { 185 | cFrame *section = ringBufferM->Get(); 186 | if (section) { 187 | uchar *data = section->Data(); 188 | int count = section->Count(); 189 | if (data && (count > 0) && (socketM[1] >= 0) && (socketM[0] >= 0)) { 190 | if (send(socketM[1], data, count, MSG_EOR) > 0) { 191 | // Update statistics 192 | AddSectionStatistic(count, 1); 193 | } 194 | else if (errno != EAGAIN) 195 | error("failed to send section data (%i bytes) [device=%d]", count, deviceIndexM); 196 | } 197 | ringBufferM->Drop(section); 198 | } 199 | } 200 | 201 | int cSatipSectionFilter::Available(void) const 202 | { 203 | return ringBufferM->Available(); 204 | } 205 | 206 | cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP) 207 | : cThread(cString::sprintf("SATIP#%d section handler", deviceIndexP)), 208 | ringBufferM(new cRingBufferLinear(bufferLenP, TS_SIZE, false, *cString::sprintf("SATIP %d section handler", deviceIndexP))), 209 | mutexM(), 210 | deviceIndexM(deviceIndexP) 211 | { 212 | debug1("%s (%d, %d) [device %d]", __PRETTY_FUNCTION__, deviceIndexM, bufferLenP, deviceIndexM); 213 | 214 | // Initialize filter pointers 215 | memset(filtersM, 0, sizeof(filtersM)); 216 | 217 | // Create input buffer 218 | if (ringBufferM) { 219 | ringBufferM->SetTimeouts(100, 100); 220 | ringBufferM->SetIoThrottle(); 221 | } 222 | else 223 | error("Failed to allocate buffer for section filter handler [device=%d]", deviceIndexM); 224 | 225 | Start(); 226 | } 227 | 228 | cSatipSectionFilterHandler::~cSatipSectionFilterHandler() 229 | { 230 | debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIndexM); 231 | // Stop thread 232 | if (Running()) 233 | Cancel(3); 234 | DELETE_POINTER(ringBufferM); 235 | 236 | // Destroy all filters 237 | cMutexLock MutexLock(&mutexM); 238 | for (int i = 0; i < eMaxSecFilterCount; ++i) 239 | Delete(i); 240 | } 241 | 242 | void cSatipSectionFilterHandler::SendAll(void) 243 | { 244 | cMutexLock MutexLock(&mutexM); 245 | bool pendingData; 246 | do { 247 | pendingData = false; 248 | 249 | // zero polling structures 250 | memset(pollFdsM, 0, sizeof(pollFdsM)); 251 | 252 | // assemble all handlers to poll (use -1 to ignore handlers) 253 | for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { 254 | if (filtersM[i] && filtersM[i]->Available() != 0) { 255 | pollFdsM[i].fd = filtersM[i]->GetFd(); 256 | pollFdsM[i].events = POLLOUT; 257 | pendingData = true; 258 | } 259 | else 260 | pollFdsM[i].fd = -1; 261 | } 262 | 263 | // exit if there isn't any pending data or we time out 264 | if (!pendingData || poll(pollFdsM, eMaxSecFilterCount, eSecFilterSendTimeoutMs) <= 0) 265 | return; 266 | 267 | // send data (if available) 268 | for (unsigned int i = 0; i < eMaxSecFilterCount && pendingData; ++i) { 269 | if (pollFdsM[i].revents & POLLOUT) 270 | filtersM[i]->Send(); 271 | } 272 | } while (pendingData); 273 | } 274 | 275 | void cSatipSectionFilterHandler::Action(void) 276 | { 277 | debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIndexM); 278 | // Do the thread loop 279 | while (Running()) { 280 | uchar *p = NULL; 281 | int len = 0; 282 | // Process all pending TS packets 283 | while ((p = ringBufferM->Get(len)) != NULL) { 284 | if (p && (len >= TS_SIZE)) { 285 | if (*p != TS_SYNC_BYTE) { 286 | for (int i = 1; i < len; ++i) { 287 | if (p[i] == TS_SYNC_BYTE) { 288 | len = i; 289 | break; 290 | } 291 | } 292 | ringBufferM->Del(len); 293 | debug1("%s Skipped %d bytes to sync on TS packet [device %d]", __PRETTY_FUNCTION__, len, deviceIndexM); 294 | continue; 295 | } 296 | // Process TS packet through all filters 297 | mutexM.Lock(); 298 | for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { 299 | if (filtersM[i]) 300 | filtersM[i]->Process(p); 301 | } 302 | mutexM.Unlock(); 303 | ringBufferM->Del(TS_SIZE); 304 | } 305 | } 306 | 307 | // Send demuxed section packets through all filters 308 | SendAll(); 309 | } 310 | debug1("%s Exiting [device %d]", __PRETTY_FUNCTION__, deviceIndexM); 311 | } 312 | 313 | cString cSatipSectionFilterHandler::GetInformation(void) 314 | { 315 | debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIndexM); 316 | // loop through active section filters 317 | cMutexLock MutexLock(&mutexM); 318 | cString s = ""; 319 | unsigned int count = 0; 320 | for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { 321 | if (filtersM[i]) { 322 | s = cString::sprintf("%sFilter %d: %s Pid=0x%02X (%s)\n", *s, i, 323 | *filtersM[i]->GetSectionStatistic(), filtersM[i]->GetPid(), 324 | id_pid(filtersM[i]->GetPid())); 325 | if (++count > SATIP_STATS_ACTIVE_FILTERS_COUNT) 326 | break; 327 | } 328 | } 329 | return s; 330 | } 331 | 332 | bool cSatipSectionFilterHandler::Exists(u_short pidP) 333 | { 334 | debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, pidP, deviceIndexM); 335 | cMutexLock MutexLock(&mutexM); 336 | for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { 337 | if (filtersM[i] && (pidP == filtersM[i]->GetPid())) { 338 | debug12("%s (%d) Found [device %d]", __PRETTY_FUNCTION__, pidP, deviceIndexM); 339 | return true; 340 | } 341 | } 342 | return false; 343 | } 344 | 345 | bool cSatipSectionFilterHandler::Delete(unsigned int indexP) 346 | { 347 | debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM); 348 | if ((indexP < eMaxSecFilterCount) && filtersM[indexP]) { 349 | debug8("%s (%d) Found [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM); 350 | cSatipSectionFilter *tmp = filtersM[indexP]; 351 | filtersM[indexP] = NULL; 352 | delete tmp; 353 | return true; 354 | } 355 | return false; 356 | } 357 | 358 | bool cSatipSectionFilterHandler::IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const 359 | { 360 | debug16("%s (%d, %02X, %02X) [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, deviceIndexM); 361 | // loop through section filter table 362 | for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) { 363 | int index = SatipConfig.GetDisabledFilters(i); 364 | // Check if matches 365 | if ((index >= 0) && (index < SECTION_FILTER_TABLE_SIZE) && 366 | (section_filter_table[index].pid == pidP) && (section_filter_table[index].tid == tidP) && 367 | (section_filter_table[index].mask == maskP)) { 368 | debug8("%s Found %s [device %d]", __PRETTY_FUNCTION__, section_filter_table[index].description, deviceIndexM); 369 | return true; 370 | } 371 | } 372 | return false; 373 | } 374 | 375 | int cSatipSectionFilterHandler::Open(u_short pidP, u_char tidP, u_char maskP) 376 | { 377 | cMutexLock MutexLock(&mutexM); 378 | // Blacklist check, refuse certain filters 379 | if (IsBlackListed(pidP, tidP, maskP)) 380 | return -1; 381 | // Search the next free filter slot 382 | for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { 383 | if (!filtersM[i]) { 384 | filtersM[i] = new cSatipSectionFilter(deviceIndexM, pidP, tidP, maskP); 385 | debug16("%s (%d, %02X, %02X) handle=%d index=%u [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, filtersM[i]->GetFd(), i, deviceIndexM); 386 | return filtersM[i]->GetFd(); 387 | } 388 | } 389 | // No free filter slot found 390 | return -1; 391 | } 392 | 393 | void cSatipSectionFilterHandler::Close(int handleP) 394 | { 395 | cMutexLock MutexLock(&mutexM); 396 | // Search the filter for deletion 397 | for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { 398 | if (filtersM[i] && (handleP == filtersM[i]->GetFd())) { 399 | debug8("%s (%d) pid=%d index=%u [device %d]", __PRETTY_FUNCTION__, handleP, filtersM[i]->GetPid(), i, deviceIndexM); 400 | Delete(i); 401 | break; 402 | } 403 | } 404 | } 405 | 406 | int cSatipSectionFilterHandler::GetPid(int handleP) 407 | { 408 | cMutexLock MutexLock(&mutexM); 409 | // Search the filter for data 410 | for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { 411 | if (filtersM[i] && (handleP == filtersM[i]->GetFd())) { 412 | debug8("%s (%d) pid=%d index=%u [device %d]", __PRETTY_FUNCTION__, handleP, filtersM[i]->GetPid(), i, deviceIndexM); 413 | return filtersM[i]->GetPid(); 414 | } 415 | } 416 | return -1; 417 | } 418 | 419 | void cSatipSectionFilterHandler::Write(uchar *bufferP, int lengthP) 420 | { 421 | debug16("%s (, %d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIndexM); 422 | // Fill up the buffer 423 | if (ringBufferM) { 424 | int len = ringBufferM->Put(bufferP, lengthP); 425 | if (len != lengthP) 426 | ringBufferM->ReportOverflow(lengthP - len); 427 | } 428 | } 429 | -------------------------------------------------------------------------------- /sectionfilter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sectionfilter.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_SECTIONFILTER_H 9 | #define __SATIP_SECTIONFILTER_H 10 | 11 | #include 12 | #include 13 | 14 | #include "common.h" 15 | #include "statistics.h" 16 | 17 | class cSatipSectionFilter : public cSatipSectionStatistics { 18 | private: 19 | enum { 20 | eDmxMaxFilterSize = 18, 21 | eDmxMaxSectionCount = 64, 22 | eDmxMaxSectionSize = 4096, 23 | eDmxMaxSectionFeedSize = (eDmxMaxSectionSize + TS_SIZE) 24 | }; 25 | 26 | int pusiSeenM; 27 | int feedCcM; 28 | int doneqM; 29 | 30 | uint8_t *secBufM; 31 | uint8_t secBufBaseM[eDmxMaxSectionFeedSize]; 32 | uint16_t secBufpM; 33 | uint16_t secLenM; 34 | uint16_t tsFeedpM; 35 | uint16_t pidM; 36 | uint8_t tidM; 37 | uint8_t maskM; 38 | 39 | cRingBufferFrame *ringBufferM; 40 | int deviceIndexM; 41 | int socketM[2]; 42 | 43 | inline uint16_t GetLength(const uint8_t *dataP); 44 | void New(void); 45 | int Filter(void); 46 | inline int Feed(void); 47 | int CopyDump(const uint8_t *bufP, uint8_t lenP); 48 | 49 | public: 50 | // constructor & destructor 51 | cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP); 52 | virtual ~cSatipSectionFilter(); 53 | void Process(const uint8_t* dataP); 54 | void Send(void); 55 | int GetFd(void) { return socketM[0]; } 56 | uint16_t GetPid(void) const { return pidM; } 57 | int Available(void) const; 58 | }; 59 | 60 | class cSatipSectionFilterHandler : public cThread { 61 | private: 62 | enum { 63 | eMaxSecFilterCount = 32, 64 | eSecFilterSendTimeoutMs = 10 65 | }; 66 | cRingBufferLinear *ringBufferM; 67 | cMutex mutexM; 68 | int deviceIndexM; 69 | cSatipSectionFilter *filtersM[eMaxSecFilterCount]; 70 | struct pollfd pollFdsM[eMaxSecFilterCount]; 71 | 72 | bool Delete(unsigned int indexP); 73 | bool IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const; 74 | void SendAll(void); 75 | 76 | protected: 77 | virtual void Action(void); 78 | 79 | public: 80 | cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP); 81 | virtual ~cSatipSectionFilterHandler(); 82 | cString GetInformation(void); 83 | bool Exists(u_short pidP); 84 | int Open(u_short pidP, u_char tidP, u_char maskP); 85 | void Close(int handleP); 86 | int GetPid(int handleP); 87 | void Write(u_char *bufferP, int lengthP); 88 | }; 89 | 90 | #endif // __SATIP_SECTIONFILTER_H 91 | -------------------------------------------------------------------------------- /server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * server.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_SERVER_H 9 | #define __SATIP_SERVER_H 10 | 11 | class cSatipServer; 12 | 13 | // --- cSatipFrontend --------------------------------------------------------- 14 | 15 | class cSatipFrontend : public cListObject { 16 | private: 17 | int indexM; 18 | int transponderM; 19 | int deviceIdM; 20 | cString descriptionM; 21 | 22 | public: 23 | cSatipFrontend(const int indexP, const char *descriptionP); 24 | virtual ~cSatipFrontend(); 25 | void Attach(int deviceIdP) { deviceIdM = deviceIdP; } 26 | void Detach(int deviceIdP) { if (deviceIdP == deviceIdM) deviceIdM = -1; } 27 | cString Description(void) { return descriptionM; } 28 | bool Attached(void) { return (deviceIdM >= 0); } 29 | int Index(void) { return indexM; } 30 | int Transponder(void) { return transponderM; } 31 | int DeviceId(void) { return deviceIdM; } 32 | void SetTransponder(int transponderP) { transponderM = transponderP; } 33 | }; 34 | 35 | // --- cSatipFrontends -------------------------------------------------------- 36 | 37 | class cSatipFrontends : public cList { 38 | public: 39 | bool Matches(int deviceIdP, int transponderP); 40 | bool Assign(int deviceIdP, int transponderP); 41 | bool Attach(int deviceIdP, int transponderP); 42 | bool Detach(int deviceIdP, int transponderP); 43 | }; 44 | 45 | // --- cSatipServer ----------------------------------------------------------- 46 | 47 | class cSatipServer : public cListObject { 48 | private: 49 | enum eSatipFrontend { 50 | eSatipFrontendDVBS2 = 0, 51 | eSatipFrontendDVBT, 52 | eSatipFrontendDVBT2, 53 | eSatipFrontendDVBC, 54 | eSatipFrontendDVBC2, 55 | eSatipFrontendATSC, 56 | eSatipFrontendCount 57 | }; 58 | enum { 59 | eSatipMaxSourceFilters = 16 60 | }; 61 | cString srcAddressM; 62 | cString addressM; 63 | cString modelM; 64 | cString filtersM; 65 | cString descriptionM; 66 | cString quirksM; 67 | cSatipFrontends frontendsM[eSatipFrontendCount]; 68 | int sourceFiltersM[eSatipMaxSourceFilters]; 69 | int portM; 70 | int quirkM; 71 | bool hasCiM; 72 | bool activeM; 73 | time_t createdM; 74 | cTimeMs lastSeenM; 75 | bool IsValidSource(int sourceP); 76 | 77 | public: 78 | enum eSatipQuirk { 79 | eSatipQuirkNone = 0x00, 80 | eSatipQuirkSessionId = 0x01, 81 | eSatipQuirkPlayPids = 0x02, 82 | eSatipQuirkForceLock = 0x04, 83 | eSatipQuirkRtpOverTcp = 0x08, 84 | eSatipQuirkCiXpmt = 0x10, 85 | eSatipQuirkCiTnr = 0x20, 86 | eSatipQuirkForcePilot = 0x40, 87 | eSatipQuirkTearAndPlay = 0x80, 88 | eSatipQuirkMask = 0xFF 89 | }; 90 | cSatipServer(const char *srcAddressP, const char *addressP, const int portP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP); 91 | virtual ~cSatipServer(); 92 | virtual int Compare(const cListObject &listObjectP) const; 93 | bool Assign(int deviceIdP, int sourceP, int systemP, int transponderP); 94 | bool Matches(int sourceP); 95 | bool Matches(int deviceIdP, int sourceP, int systemP, int transponderP); 96 | void Attach(int deviceIdP, int transponderP); 97 | void Detach(int deviceIdP, int transponderP); 98 | int GetModulesDVBS2(void); 99 | int GetModulesDVBT(void); 100 | int GetModulesDVBT2(void); 101 | int GetModulesDVBC(void); 102 | int GetModulesDVBC2(void); 103 | int GetModulesATSC(void); 104 | void Activate(bool onOffP) { activeM = onOffP; } 105 | const char *SrcAddress(void) { return *srcAddressM; } 106 | const char *Address(void) { return *addressM; } 107 | const char *Model(void) { return *modelM; } 108 | const char *Filters(void) { return *filtersM; } 109 | const char *Description(void) { return *descriptionM; } 110 | const char *Quirks(void) { return *quirksM; } 111 | int Port(void) { return portM; } 112 | bool Quirk(int quirkP) { return ((quirkP & eSatipQuirkMask) & quirkM); } 113 | bool HasQuirk(void) { return (quirkM != eSatipQuirkNone); } 114 | bool HasCI(void) { return hasCiM; } 115 | bool IsActive(void) { return activeM; } 116 | void Update(void) { lastSeenM.Set(); } 117 | uint64_t LastSeen(void) { return lastSeenM.Elapsed(); } 118 | time_t Created(void) { return createdM; } 119 | }; 120 | 121 | // --- cSatipServers ---------------------------------------------------------- 122 | 123 | class cSatipServers : public cList { 124 | public: 125 | cSatipServer *Find(cSatipServer *serverP); 126 | cSatipServer *Find(int sourceP); 127 | cSatipServer *Assign(int deviceIdP, int sourceP, int transponderP, int systemP); 128 | cSatipServer *Update(cSatipServer *serverP); 129 | void Activate(cSatipServer *serverP, bool onOffP); 130 | void Attach(cSatipServer *serverP, int deviceIdP, int transponderP); 131 | void Detach(cSatipServer *serverP, int deviceIdP, int transponderP); 132 | bool IsQuirk(cSatipServer *serverP, int quirkP); 133 | bool HasCI(cSatipServer *serverP); 134 | void Cleanup(uint64_t intervalMsP = 0); 135 | cString GetAddress(cSatipServer *serverP); 136 | cString GetSrcAddress(cSatipServer *serverP); 137 | cString GetString(cSatipServer *serverP); 138 | int GetPort(cSatipServer *serverP); 139 | cString List(void); 140 | int NumProvidedSystems(void); 141 | }; 142 | 143 | #endif // __SATIP_SERVER_H 144 | -------------------------------------------------------------------------------- /setup.h: -------------------------------------------------------------------------------- 1 | /* 2 | * setup.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_SETUP_H 9 | #define __SATIP_SETUP_H 10 | 11 | #include 12 | #include 13 | #include "common.h" 14 | 15 | class cSatipPluginSetup : public cMenuSetupPage 16 | { 17 | private: 18 | bool detachedModeM; 19 | int deviceCountM; 20 | int operatingModeM; 21 | int transportModeM; 22 | const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount]; 23 | const char *transportModeTextsM[cSatipConfig::eTransportModeCount]; 24 | int ciExtensionM; 25 | int frontendReuseM; 26 | int cicamsM[MAX_CICAM_COUNT]; 27 | const char *cicamTextsM[CA_SYSTEMS_TABLE_SIZE]; 28 | int eitScanM; 29 | int numDisabledSourcesM; 30 | int disabledSourcesM[MAX_DISABLED_SOURCES_COUNT]; 31 | int numDisabledFiltersM; 32 | int disabledFilterIndexesM[SECTION_FILTER_TABLE_SIZE]; 33 | const char *disabledFilterNamesM[SECTION_FILTER_TABLE_SIZE]; 34 | cVector helpM; 35 | 36 | eOSState DeviceScan(void); 37 | eOSState DeviceInfo(void); 38 | eOSState ShowDeviceStatus(void); 39 | eOSState ShowInfo(void); 40 | void Setup(void); 41 | void StoreCicams(const char *nameP, int *cicamsP); 42 | void StoreSources(const char *nameP, int *sourcesP); 43 | void StoreFilters(const char *nameP, int *valuesP); 44 | 45 | protected: 46 | virtual eOSState ProcessKey(eKeys keyP); 47 | virtual void Store(void); 48 | 49 | public: 50 | cSatipPluginSetup(); 51 | }; 52 | 53 | #endif // __SATIP_SETUP_H 54 | -------------------------------------------------------------------------------- /socket.c: -------------------------------------------------------------------------------- 1 | /* 2 | * socket.c: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "common.h" 18 | #include "config.h" 19 | #include "log.h" 20 | #include "socket.h" 21 | 22 | #if defined(__GLIBC__) 23 | #if defined(__GLIBC_PREREQ) 24 | #if !__GLIBC_PREREQ(2,12) 25 | #define __SATIP_DISABLE_RECVMMSG__ 26 | #endif 27 | #endif 28 | #endif 29 | 30 | cSatipSocket::cSatipSocket() 31 | : socketPortM(0), 32 | socketDescM(-1), 33 | isMulticastM(false), 34 | useSsmM(false), 35 | streamAddrM(htonl(INADDR_ANY)), 36 | sourceAddrM(htonl(INADDR_ANY)), 37 | rcvBufSizeM(0) 38 | { 39 | debug1("%s", __PRETTY_FUNCTION__); 40 | memset(&sockAddrM, 0, sizeof(sockAddrM)); 41 | } 42 | 43 | cSatipSocket::cSatipSocket(size_t rcvBufSizeP) 44 | : socketPortM(0), 45 | socketDescM(-1), 46 | isMulticastM(false), 47 | useSsmM(false), 48 | streamAddrM(htonl(INADDR_ANY)), 49 | sourceAddrM(htonl(INADDR_ANY)), 50 | rcvBufSizeM(rcvBufSizeP) 51 | { 52 | debug1("%s", __PRETTY_FUNCTION__); 53 | memset(&sockAddrM, 0, sizeof(sockAddrM)); 54 | } 55 | 56 | cSatipSocket::~cSatipSocket() 57 | { 58 | debug1("%s", __PRETTY_FUNCTION__); 59 | // Close the socket 60 | Close(); 61 | } 62 | 63 | bool cSatipSocket::Open(const int portP, const bool reuseP) 64 | { 65 | // If socket is there already and it is bound to a different port, it must 66 | // be closed first 67 | if (portP != socketPortM) { 68 | debug1("%s (%d, %d) Socket tear-down", __PRETTY_FUNCTION__, portP, reuseP); 69 | Close(); 70 | } 71 | // Bind to the socket if it is not active already 72 | if (socketDescM < 0) { 73 | int yes; 74 | socklen_t len = sizeof(sockAddrM); 75 | // Create socket 76 | socketDescM = socket(PF_INET, SOCK_DGRAM, 0); 77 | ERROR_IF_RET(socketDescM < 0, "socket()", return false); 78 | // Make it use non-blocking I/O to avoid stuck read calls 79 | ERROR_IF_FUNC(fcntl(socketDescM, F_SETFL, O_NONBLOCK), "fcntl(O_NONBLOCK)", 80 | Close(), return false); 81 | // Allow multiple sockets to use the same PORT number 82 | yes = reuseP; 83 | ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0, 84 | "setsockopt(SO_REUSEADDR)", Close(), return false); 85 | yes = reuseP; 86 | #ifdef SO_REUSEPORT 87 | ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0 && errno != ENOPROTOOPT, 88 | "setsockopt(SO_REUSEPORT)", Close(), return false); 89 | #endif 90 | #ifndef __FreeBSD__ 91 | // Allow packet information to be fetched 92 | ERROR_IF_FUNC(setsockopt(socketDescM, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0, 93 | "setsockopt(IP_PKTINFO)", Close(), return false); 94 | #endif // __FreeBSD__ 95 | // Tweak receive buffer size if requested 96 | if (rcvBufSizeM > 0) { 97 | ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_RCVBUF, &rcvBufSizeM, sizeof(rcvBufSizeM)) < 0, 98 | "setsockopt(SO_RCVBUF)", Close(), return false); 99 | } 100 | // Bind socket 101 | memset(&sockAddrM, 0, sizeof(sockAddrM)); 102 | sockAddrM.sin_family = AF_INET; 103 | sockAddrM.sin_port = htons((uint16_t)(portP & 0xFFFF)); 104 | sockAddrM.sin_addr.s_addr = htonl(INADDR_ANY); 105 | ERROR_IF_FUNC(bind(socketDescM, (struct sockaddr *)&sockAddrM, sizeof(sockAddrM)) < 0, 106 | "bind()", Close(), return false); 107 | // Update socket port 108 | ERROR_IF_FUNC(getsockname(socketDescM, (struct sockaddr*)&sockAddrM, &len) < 0, 109 | "getsockname()", Close(), return false); 110 | socketPortM = ntohs(sockAddrM.sin_port); 111 | isMulticastM = false; 112 | } 113 | debug1("%s (%d) socketPort=%d", __PRETTY_FUNCTION__, portP, socketPortM); 114 | return true; 115 | } 116 | 117 | bool cSatipSocket::OpenMulticast(const int portP, const char *streamAddrP, const char *sourceAddrP) 118 | { 119 | debug1("%s (%d, %s, %s)", __PRETTY_FUNCTION__, portP, streamAddrP, sourceAddrP); 120 | if (Open(portP)) { 121 | CheckAddress(streamAddrP, &streamAddrM); 122 | if (!isempty(sourceAddrP)) 123 | useSsmM = CheckAddress(sourceAddrP, &sourceAddrM); 124 | return Join(); 125 | } 126 | return false; 127 | } 128 | 129 | void cSatipSocket::Close(void) 130 | { 131 | debug1("%s socketPort=%d", __PRETTY_FUNCTION__, socketPortM); 132 | // Check if socket exists 133 | if (socketDescM >= 0) { 134 | Leave(); 135 | close(socketDescM); 136 | socketDescM = -1; 137 | socketPortM = 0; 138 | memset(&sockAddrM, 0, sizeof(sockAddrM)); 139 | streamAddrM = htonl(INADDR_ANY); 140 | sourceAddrM = htonl(INADDR_ANY); 141 | isMulticastM = false; 142 | useSsmM = false; 143 | } 144 | } 145 | 146 | bool cSatipSocket::Flush(void) 147 | { 148 | debug1("%s", __PRETTY_FUNCTION__); 149 | if (socketDescM < 0) { 150 | const unsigned int len = 65535; 151 | unsigned char *buf = MALLOC(unsigned char, len); 152 | if (buf) { 153 | int i = 0; 154 | do { 155 | // Sanity check 156 | if (++i > 10) 157 | break; 158 | } while (Read(buf, len)); 159 | return true; 160 | } 161 | } 162 | return false; 163 | } 164 | 165 | bool cSatipSocket::CheckAddress(const char *addrP, in_addr_t *inAddrP) 166 | { 167 | if (inAddrP) { 168 | // First try only the IP address 169 | *inAddrP = inet_addr(addrP); 170 | if (*inAddrP == htonl(INADDR_NONE)) { 171 | debug1("%s (%s, ) Cannot convert to address", __PRETTY_FUNCTION__, addrP); 172 | // It may be a host name, get the name 173 | struct hostent *host = gethostbyname(addrP); 174 | if (!host) { 175 | char tmp[64]; 176 | error("gethostbyname() failed: %s is not valid address: %s", addrP, 177 | strerror_r(h_errno, tmp, sizeof(tmp))); 178 | return false; 179 | } 180 | *inAddrP = inet_addr(*host->h_addr_list); 181 | } 182 | return true; 183 | } 184 | return false; 185 | } 186 | 187 | bool cSatipSocket::Join(void) 188 | { 189 | debug1("%s", __PRETTY_FUNCTION__); 190 | // Check if socket exists 191 | if (socketDescM >= 0 && !isMulticastM) { 192 | // Join a new multicast group 193 | if (useSsmM) { 194 | // Source-specific multicast (SSM) is used 195 | struct group_source_req gsr; 196 | struct sockaddr_in *grp; 197 | struct sockaddr_in *src; 198 | gsr.gsr_interface = 0; // if_nametoindex("any") ? 199 | grp = (struct sockaddr_in*)&gsr.gsr_group; 200 | grp->sin_family = AF_INET; 201 | grp->sin_addr.s_addr = streamAddrM; 202 | grp->sin_port = 0; 203 | src = (struct sockaddr_in*)&gsr.gsr_source; 204 | src->sin_family = AF_INET; 205 | src->sin_addr.s_addr = sourceAddrM; 206 | src->sin_port = 0; 207 | ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_JOIN_SOURCE_GROUP)", return false); 208 | } 209 | else { 210 | struct ip_mreq mreq; 211 | mreq.imr_multiaddr.s_addr = streamAddrM; 212 | mreq.imr_interface.s_addr = htonl(INADDR_ANY); 213 | ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_ADD_MEMBERSHIP)", return false); 214 | } 215 | // Update multicasting flag 216 | isMulticastM = true; 217 | } 218 | return true; 219 | } 220 | 221 | bool cSatipSocket::Leave(void) 222 | { 223 | debug1("%s", __PRETTY_FUNCTION__); 224 | // Check if socket exists 225 | if (socketDescM >= 0 && isMulticastM) { 226 | // Leave the existing multicast group 227 | if (useSsmM) { 228 | // Source-specific multicast (SSM) is used 229 | struct group_source_req gsr; 230 | struct sockaddr_in *grp; 231 | struct sockaddr_in *src; 232 | gsr.gsr_interface = 0; // if_nametoindex("any") ? 233 | grp = (struct sockaddr_in*)&gsr.gsr_group; 234 | grp->sin_family = AF_INET; 235 | grp->sin_addr.s_addr = streamAddrM; 236 | grp->sin_port = 0; 237 | src = (struct sockaddr_in*)&gsr.gsr_source; 238 | src->sin_family = AF_INET; 239 | src->sin_addr.s_addr = sourceAddrM; 240 | src->sin_port = 0; 241 | ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, MCAST_LEAVE_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_LEAVE_SOURCE_GROUP)", return false); 242 | } 243 | else { 244 | struct ip_mreq mreq; 245 | mreq.imr_multiaddr.s_addr = streamAddrM; 246 | mreq.imr_interface.s_addr = htonl(INADDR_ANY); 247 | ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_DROP_MEMBERSHIP)", return false); 248 | } 249 | // Update multicasting flag 250 | isMulticastM = false; 251 | } 252 | return true; 253 | } 254 | 255 | int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP) 256 | { 257 | debug16("%s (, %d)", __PRETTY_FUNCTION__, bufferLenP); 258 | // Error out if socket not initialized 259 | if (socketDescM <= 0) { 260 | error("%s Invalid socket", __PRETTY_FUNCTION__); 261 | return -1; 262 | } 263 | int len = 0; 264 | // Read data from socket in a loop 265 | do { 266 | socklen_t addrlen = sizeof(sockAddrM); 267 | struct msghdr msgh; 268 | struct iovec iov; 269 | char cbuf[256]; 270 | len = 0; 271 | // Initialize iov and msgh structures 272 | memset(&msgh, 0, sizeof(struct msghdr)); 273 | iov.iov_base = bufferAddrP; 274 | iov.iov_len = bufferLenP; 275 | msgh.msg_control = cbuf; 276 | msgh.msg_controllen = sizeof(cbuf); 277 | msgh.msg_name = &sockAddrM; 278 | msgh.msg_namelen = addrlen; 279 | msgh.msg_iov = &iov; 280 | msgh.msg_iovlen = 1; 281 | msgh.msg_flags = 0; 282 | 283 | if (socketDescM && bufferAddrP && (bufferLenP > 0)) 284 | len = (int)recvmsg(socketDescM, &msgh, MSG_DONTWAIT); 285 | if (len > 0) { 286 | #ifndef __FreeBSD__ 287 | if (isMulticastM) { 288 | // Process auxiliary received data and validate source address 289 | for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) { 290 | if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { 291 | struct in_pktinfo *i = (struct in_pktinfo *)CMSG_DATA(cmsg); 292 | if ((i->ipi_addr.s_addr == streamAddrM) || (htonl(INADDR_ANY) == streamAddrM)) 293 | return len; 294 | } 295 | } 296 | } 297 | else 298 | #endif // __FreeBSD__ 299 | return len; 300 | } 301 | } while (len > 0); 302 | ERROR_IF_RET(len < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmsg()", return -1); 303 | return 0; 304 | } 305 | 306 | int cSatipSocket::ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRecvSizeP, unsigned int elementCountP, unsigned int elementBufferSizeP) 307 | { 308 | debug16("%s (, , %d, %d)", __PRETTY_FUNCTION__, elementCountP, elementBufferSizeP); 309 | int count = -1; 310 | // Error out if socket not initialized 311 | if (socketDescM <= 0) { 312 | error("%s Invalid socket", __PRETTY_FUNCTION__); 313 | return -1; 314 | } 315 | if (!bufferAddrP || !elementRecvSizeP || !elementCountP || !elementBufferSizeP) { 316 | error("%s Invalid parameter(s)", __PRETTY_FUNCTION__); 317 | return -1; 318 | } 319 | #ifndef __SATIP_DISABLE_RECVMMSG__ 320 | // Initialize iov and msgh structures 321 | struct mmsghdr mmsgh[elementCountP]; 322 | struct iovec iov[elementCountP]; 323 | memset(mmsgh, 0, sizeof(mmsgh[0]) * elementCountP); 324 | for (unsigned int i = 0; i < elementCountP; ++i) { 325 | iov[i].iov_base = bufferAddrP + i * elementBufferSizeP; 326 | iov[i].iov_len = elementBufferSizeP; 327 | mmsgh[i].msg_hdr.msg_iov = &iov[i]; 328 | mmsgh[i].msg_hdr.msg_iovlen = 1; 329 | } 330 | 331 | // Read data from socket as a set 332 | count = (int)recvmmsg(socketDescM, mmsgh, elementCountP, MSG_DONTWAIT, NULL); 333 | ERROR_IF_RET(count < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmmsg()", return -1); 334 | for (int i = 0; i < count; ++i) 335 | elementRecvSizeP[i] = mmsgh[i].msg_len; 336 | #else 337 | count = 0; 338 | while (count < (int)elementCountP) { 339 | int len = Read(bufferAddrP + count * elementBufferSizeP, elementBufferSizeP); 340 | if (len < 0) 341 | return -1; 342 | else if (len == 0) 343 | break; 344 | elementRecvSizeP[count++] = len; 345 | } 346 | #endif 347 | debug16("%s Received %d packets size[0]=%d", __PRETTY_FUNCTION__, count, elementRecvSizeP[0]); 348 | 349 | return count; 350 | } 351 | 352 | 353 | bool cSatipSocket::Write(const char *addrP, const unsigned char *bufferAddrP, unsigned int bufferLenP) 354 | { 355 | debug1("%s (%s, , %d)", __PRETTY_FUNCTION__, addrP, bufferLenP); 356 | // Error out if socket not initialized 357 | if (socketDescM <= 0) { 358 | error("%s Invalid socket", __PRETTY_FUNCTION__); 359 | return false; 360 | } 361 | struct sockaddr_in sockAddr; 362 | memset(&sockAddr, 0, sizeof(sockAddr)); 363 | sockAddr.sin_family = AF_INET; 364 | sockAddr.sin_port = htons((uint16_t)(socketPortM & 0xFFFF)); 365 | sockAddr.sin_addr.s_addr = inet_addr(addrP); 366 | ERROR_IF_RET(sendto(socketDescM, bufferAddrP, bufferLenP, 0, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) < 0, "sendto()", return false); 367 | return true; 368 | } 369 | -------------------------------------------------------------------------------- /socket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * socket.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_SOCKET_H 9 | #define __SATIP_SOCKET_H 10 | 11 | #include 12 | 13 | class cSatipSocket { 14 | private: 15 | int socketPortM; 16 | int socketDescM; 17 | struct sockaddr_in sockAddrM; 18 | bool isMulticastM; 19 | bool useSsmM; 20 | in_addr_t streamAddrM; 21 | in_addr_t sourceAddrM; 22 | size_t rcvBufSizeM; 23 | 24 | bool CheckAddress(const char *addrP, in_addr_t *inAddrP); 25 | bool Join(void); 26 | bool Leave(void); 27 | 28 | public: 29 | cSatipSocket(); 30 | explicit cSatipSocket(size_t rcvBufSizeP); 31 | virtual ~cSatipSocket(); 32 | bool Open(const int portP = 0, const bool reuseP = false); 33 | bool OpenMulticast(const int portP, const char *streamAddrP, const char *sourceAddrP); 34 | virtual void Close(void); 35 | int Fd(void) { return socketDescM; } 36 | int Port(void) { return socketPortM; } 37 | bool IsMulticast(void) { return isMulticastM; } 38 | bool IsOpen(void) { return (socketDescM >= 0); } 39 | bool Flush(void); 40 | int Read(unsigned char *bufferAddrP, unsigned int bufferLenP); 41 | int ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRecvSizeP, unsigned int elementCountP, unsigned int elementBufferSizeP); 42 | bool Write(const char *addrP, const unsigned char *bufferAddrP, unsigned int bufferLenP); 43 | }; 44 | 45 | #endif // __SATIP_SOCKET_H 46 | 47 | -------------------------------------------------------------------------------- /statistics.c: -------------------------------------------------------------------------------- 1 | /* 2 | * statistics.c: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include "common.h" 11 | #include "statistics.h" 12 | #include "log.h" 13 | #include "config.h" 14 | 15 | // Section statistics class 16 | cSatipSectionStatistics::cSatipSectionStatistics() 17 | : filteredDataM(0), 18 | numberOfCallsM(0), 19 | timerM(), 20 | mutexM() 21 | { 22 | debug16("%s", __PRETTY_FUNCTION__); 23 | } 24 | 25 | cSatipSectionStatistics::~cSatipSectionStatistics() 26 | { 27 | debug16("%s", __PRETTY_FUNCTION__); 28 | } 29 | 30 | cString cSatipSectionStatistics::GetSectionStatistic() 31 | { 32 | debug16("%s", __PRETTY_FUNCTION__); 33 | cMutexLock MutexLock(&mutexM); 34 | uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */ 35 | timerM.Set(); 36 | long bitrate = elapsed ? (long)(1000.0L * filteredDataM / KILOBYTE(1) / elapsed) : 0L; 37 | if (!SatipConfig.GetUseBytes()) 38 | bitrate *= 8; 39 | // no trailing linefeed here! 40 | cString s = cString::sprintf("%4ld (%4ld k%s/s)", numberOfCallsM, bitrate, 41 | SatipConfig.GetUseBytes() ? "B" : "bit"); 42 | filteredDataM = numberOfCallsM = 0; 43 | return s; 44 | } 45 | 46 | void cSatipSectionStatistics::AddSectionStatistic(long bytesP, long callsP) 47 | { 48 | debug16("%s (%ld, %ld)", __PRETTY_FUNCTION__, bytesP, callsP); 49 | cMutexLock MutexLock(&mutexM); 50 | filteredDataM += bytesP; 51 | numberOfCallsM += callsP; 52 | } 53 | 54 | // --- cSatipPidStatistics ---------------------------------------------------- 55 | 56 | // Device statistics class 57 | cSatipPidStatistics::cSatipPidStatistics() 58 | : timerM(), 59 | mutexM() 60 | { 61 | debug1("%s", __PRETTY_FUNCTION__); 62 | const int numberOfElements = sizeof(mostActivePidsM) / sizeof(pidStruct); 63 | for (int i = 0; i < numberOfElements; ++i) { 64 | mostActivePidsM[i].pid = -1; 65 | mostActivePidsM[i].dataAmount = 0L; 66 | } 67 | } 68 | 69 | cSatipPidStatistics::~cSatipPidStatistics() 70 | { 71 | debug1("%s", __PRETTY_FUNCTION__); 72 | } 73 | 74 | cString cSatipPidStatistics::GetPidStatistic() 75 | { 76 | debug16("%s", __PRETTY_FUNCTION__); 77 | cMutexLock MutexLock(&mutexM); 78 | const int numberOfElements = sizeof(mostActivePidsM) / sizeof(pidStruct); 79 | uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */ 80 | timerM.Set(); 81 | cString s("Active pids:\n"); 82 | for (int i = 0; i < numberOfElements; ++i) { 83 | if (mostActivePidsM[i].pid >= 0) { 84 | long bitrate = elapsed ? (long)(1000.0L * mostActivePidsM[i].dataAmount / KILOBYTE(1) / elapsed) : 0L; 85 | if (!SatipConfig.GetUseBytes()) 86 | bitrate *= 8; 87 | s = cString::sprintf("%sPid %d: %4d (%4ld k%s/s)\n", *s, i, 88 | mostActivePidsM[i].pid, bitrate, 89 | SatipConfig.GetUseBytes() ? "B" : "bit"); 90 | } 91 | } 92 | for (int i = 0; i < numberOfElements; ++i) { 93 | mostActivePidsM[i].pid = -1; 94 | mostActivePidsM[i].dataAmount = 0L; 95 | } 96 | return s; 97 | } 98 | 99 | int cSatipPidStatistics::SortPids(const void* data1P, const void* data2P) 100 | { 101 | debug16("%s", __PRETTY_FUNCTION__); 102 | const pidStruct *comp1 = reinterpret_cast(data1P); 103 | const pidStruct *comp2 = reinterpret_cast(data2P); 104 | if (comp1->dataAmount > comp2->dataAmount) 105 | return -1; 106 | if (comp1->dataAmount < comp2->dataAmount) 107 | return 1; 108 | return 0; 109 | } 110 | 111 | void cSatipPidStatistics::AddPidStatistic(int pidP, long payloadP) 112 | { 113 | debug16("%s (%d, %ld)", __PRETTY_FUNCTION__, pidP, payloadP); 114 | cMutexLock MutexLock(&mutexM); 115 | const int numberOfElements = sizeof(mostActivePidsM) / sizeof(pidStruct); 116 | // If our statistic already is in the array, update it and quit 117 | for (int i = 0; i < numberOfElements; ++i) { 118 | if (mostActivePidsM[i].pid == pidP) { 119 | mostActivePidsM[i].dataAmount += payloadP; 120 | // Now re-sort the array and quit 121 | qsort(mostActivePidsM, numberOfElements, sizeof(pidStruct), SortPids); 122 | return; 123 | } 124 | } 125 | // Apparently our pid isn't in the array. Replace the last element with this 126 | // one if new payload is greater 127 | if (mostActivePidsM[numberOfElements - 1].dataAmount < payloadP) { 128 | mostActivePidsM[numberOfElements - 1].pid = pidP; 129 | mostActivePidsM[numberOfElements - 1].dataAmount = payloadP; 130 | // Re-sort 131 | qsort(mostActivePidsM, numberOfElements, sizeof(pidStruct), SortPids); 132 | } 133 | } 134 | 135 | // --- cSatipTunerStatistics -------------------------------------------------- 136 | 137 | // Tuner statistics class 138 | cSatipTunerStatistics::cSatipTunerStatistics() 139 | : dataBytesM(0), 140 | timerM(), 141 | mutexM() 142 | { 143 | debug1("%s", __PRETTY_FUNCTION__); 144 | } 145 | 146 | cSatipTunerStatistics::~cSatipTunerStatistics() 147 | { 148 | debug1("%s", __PRETTY_FUNCTION__); 149 | } 150 | 151 | cString cSatipTunerStatistics::GetTunerStatistic() 152 | { 153 | debug16("%s", __PRETTY_FUNCTION__); 154 | mutexM.Lock(); 155 | uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */ 156 | timerM.Set(); 157 | long bitrate = elapsed ? (long)(1000.0L * dataBytesM / KILOBYTE(1) / elapsed) : 0L; 158 | dataBytesM = 0; 159 | mutexM.Unlock(); 160 | 161 | if (!SatipConfig.GetUseBytes()) 162 | bitrate *= 8; 163 | cString s = cString::sprintf("%ld k%s/s", bitrate, SatipConfig.GetUseBytes() ? "B" : "bit"); 164 | return s; 165 | } 166 | 167 | void cSatipTunerStatistics::AddTunerStatistic(long bytesP) 168 | { 169 | debug16("%s (%ld)", __PRETTY_FUNCTION__, bytesP); 170 | cMutexLock MutexLock(&mutexM); 171 | dataBytesM += bytesP; 172 | } 173 | 174 | 175 | // Buffer statistics class 176 | cSatipBufferStatistics::cSatipBufferStatistics() 177 | : dataBytesM(0), 178 | freeSpaceM(0), 179 | usedSpaceM(0), 180 | timerM(), 181 | mutexM() 182 | { 183 | debug1("%s", __PRETTY_FUNCTION__); 184 | } 185 | 186 | cSatipBufferStatistics::~cSatipBufferStatistics() 187 | { 188 | debug1("%s", __PRETTY_FUNCTION__); 189 | } 190 | 191 | cString cSatipBufferStatistics::GetBufferStatistic() 192 | { 193 | debug16("%s", __PRETTY_FUNCTION__); 194 | cMutexLock MutexLock(&mutexM); 195 | uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */ 196 | timerM.Set(); 197 | long bitrate = elapsed ? (long)(1000.0L * dataBytesM / KILOBYTE(1) / elapsed) : 0L; 198 | long totalSpace = SATIP_BUFFER_SIZE; 199 | float percentage = (float)((float)usedSpaceM / (float)totalSpace * 100.0); 200 | long totalKilos = totalSpace / KILOBYTE(1); 201 | long usedKilos = usedSpaceM / KILOBYTE(1); 202 | if (!SatipConfig.GetUseBytes()) { 203 | bitrate *= 8; 204 | totalKilos *= 8; 205 | usedKilos *= 8; 206 | } 207 | cString s = cString::sprintf("Buffer bitrate: %ld k%s/s\nBuffer usage: %ld/%ld k%s (%2.1f%%)\n", bitrate, 208 | SatipConfig.GetUseBytes() ? "B" : "bit", usedKilos, totalKilos, 209 | SatipConfig.GetUseBytes() ? "B" : "bit", percentage); 210 | dataBytesM = 0; 211 | usedSpaceM = 0; 212 | return s; 213 | } 214 | 215 | void cSatipBufferStatistics::AddBufferStatistic(long bytesP, long usedP) 216 | { 217 | debug16("%s (%ld, %ld)", __PRETTY_FUNCTION__, bytesP, usedP); 218 | cMutexLock MutexLock(&mutexM); 219 | dataBytesM += bytesP; 220 | if (usedP > usedSpaceM) 221 | usedSpaceM = usedP; 222 | } 223 | -------------------------------------------------------------------------------- /statistics.h: -------------------------------------------------------------------------------- 1 | /* 2 | * statistics.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_STATISTICS_H 9 | #define __SATIP_STATISTICS_H 10 | 11 | #include 12 | 13 | // Section statistics 14 | class cSatipSectionStatistics { 15 | public: 16 | cSatipSectionStatistics(); 17 | virtual ~cSatipSectionStatistics(); 18 | cString GetSectionStatistic(); 19 | 20 | protected: 21 | void AddSectionStatistic(long bytesP, long callsP); 22 | 23 | private: 24 | long filteredDataM; 25 | long numberOfCallsM; 26 | cTimeMs timerM; 27 | cMutex mutexM; 28 | }; 29 | 30 | // Pid statistics 31 | class cSatipPidStatistics { 32 | public: 33 | cSatipPidStatistics(); 34 | virtual ~cSatipPidStatistics(); 35 | cString GetPidStatistic(); 36 | 37 | protected: 38 | void AddPidStatistic(int pidP, long payloadP); 39 | 40 | private: 41 | struct pidStruct { 42 | int pid; 43 | long dataAmount; 44 | }; 45 | pidStruct mostActivePidsM[SATIP_STATS_ACTIVE_PIDS_COUNT]; 46 | cTimeMs timerM; 47 | cMutex mutexM; 48 | 49 | private: 50 | static int SortPids(const void* data1P, const void* data2P); 51 | }; 52 | 53 | // Tuner statistics 54 | class cSatipTunerStatistics { 55 | public: 56 | cSatipTunerStatistics(); 57 | virtual ~cSatipTunerStatistics(); 58 | cString GetTunerStatistic(); 59 | 60 | protected: 61 | void AddTunerStatistic(long bytesP); 62 | 63 | private: 64 | long dataBytesM; 65 | cTimeMs timerM; 66 | cMutex mutexM; 67 | }; 68 | 69 | // Buffer statistics 70 | class cSatipBufferStatistics { 71 | public: 72 | cSatipBufferStatistics(); 73 | virtual ~cSatipBufferStatistics(); 74 | cString GetBufferStatistic(); 75 | 76 | protected: 77 | void AddBufferStatistic(long bytesP, long usedP); 78 | 79 | private: 80 | long dataBytesM; 81 | long freeSpaceM; 82 | long usedSpaceM; 83 | cTimeMs timerM; 84 | cMutex mutexM; 85 | }; 86 | 87 | #endif // __SATIP_STATISTICS_H 88 | -------------------------------------------------------------------------------- /tuner.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tuner.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_TUNER_H 9 | #define __SATIP_TUNER_H 10 | 11 | #include 12 | #include 13 | 14 | #include "deviceif.h" 15 | #include "discover.h" 16 | #include "rtp.h" 17 | #include "rtcp.h" 18 | #include "rtsp.h" 19 | #include "server.h" 20 | #include "statistics.h" 21 | 22 | class cSatipPid : public cVector { 23 | private: 24 | static int PidCompare(const void *aPidP, const void *bPidP) 25 | { 26 | return (*(int*)aPidP - *(int*)bPidP); 27 | } 28 | 29 | public: 30 | void RemovePid(const int &pidP) 31 | { 32 | if (RemoveElement(pidP)) 33 | Sort(PidCompare); 34 | } 35 | void AddPid(int pidP) 36 | { 37 | if (AppendUnique(pidP)) 38 | Sort(PidCompare); 39 | } 40 | cString ListPids(void) 41 | { 42 | cString list = ""; 43 | if (Size()) { 44 | for (int i = 0; i < Size(); ++i) 45 | list = cString::sprintf("%s%d,", *list, At(i)); 46 | list = list.Truncate(-1); 47 | } 48 | return list; 49 | } 50 | }; 51 | 52 | class cSatipTunerServer 53 | { 54 | private: 55 | cSatipServer *serverM; 56 | int deviceIdM; 57 | int transponderM; 58 | 59 | public: 60 | cSatipTunerServer(cSatipServer *serverP, const int deviceIdP, const int transponderP) : serverM(serverP), deviceIdM(deviceIdP), transponderM(transponderP) {} 61 | ~cSatipTunerServer() {} 62 | cSatipTunerServer(const cSatipTunerServer &objP) { serverM = NULL; deviceIdM = -1; transponderM = 0; } 63 | cSatipTunerServer& operator= (const cSatipTunerServer &objP) { serverM = objP.serverM; deviceIdM = objP.deviceIdM; transponderM = objP.transponderM; return *this; } 64 | bool IsValid(void) { return !!serverM; } 65 | bool IsQuirk(int quirkP) { return (serverM && cSatipDiscover::GetInstance()->IsServerQuirk(serverM, quirkP)); } 66 | bool HasCI(void) { return (serverM && cSatipDiscover::GetInstance()->HasServerCI(serverM)); } 67 | void Attach(void) { if (serverM) cSatipDiscover::GetInstance()->AttachServer(serverM, deviceIdM, transponderM); } 68 | void Detach(void) { if (serverM) cSatipDiscover::GetInstance()->DetachServer(serverM, deviceIdM, transponderM); } 69 | void Set(cSatipServer *serverP, const int transponderP) { serverM = serverP; transponderM = transponderP; } 70 | void Reset(void) { serverM = NULL; transponderM = 0; } 71 | cString GetAddress(void) { return serverM ? cSatipDiscover::GetInstance()->GetServerAddress(serverM) : ""; } 72 | cString GetSrcAddress(void) { return serverM ? cSatipDiscover::GetInstance()->GetSourceAddress(serverM) : ""; } 73 | int GetPort(void) { return serverM ? cSatipDiscover::GetInstance()->GetServerPort(serverM) : SATIP_DEFAULT_RTSP_PORT; } 74 | cString GetInfo(void) { return cString::sprintf("server=%s deviceid=%d transponder=%d", serverM ? "assigned" : "null", deviceIdM, transponderM); } 75 | }; 76 | 77 | class cSatipTuner : public cThread, public cSatipTunerStatistics, public cSatipTunerIf 78 | { 79 | private: 80 | enum { 81 | eDummyPid = 100, 82 | eDefaultSignalStrengthDBm = -25, 83 | eDefaultSignalStrength = 224, 84 | eDefaultSignalQuality = 15, 85 | eSleepTimeoutMs = 250, // in milliseconds 86 | eStatusUpdateTimeoutMs = 1000, // in milliseconds 87 | ePidUpdateIntervalMs = 250, // in milliseconds 88 | eConnectTimeoutMs = 5000, // in milliseconds 89 | eIdleCheckTimeoutMs = 15000, // in milliseconds 90 | eTuningTimeoutMs = 20000, // in milliseconds 91 | eMinKeepAliveIntervalMs = 30000, // in milliseconds 92 | eKeepAlivePreBufferMs = 2000, // in milliseconds 93 | eSetupTimeoutMs = 2000 // in milliseconds 94 | }; 95 | enum eTunerState { tsIdle, tsRelease, tsSet, tsTuned, tsLocked }; 96 | enum eStateMode { smInternal, smExternal }; 97 | 98 | cCondWait sleepM; 99 | cSatipDeviceIf* deviceM; 100 | int deviceIdM; 101 | cSatipRtsp rtspM; 102 | cSatipRtp rtpM; 103 | cSatipRtcp rtcpM; 104 | cString streamAddrM; 105 | cString streamParamM; 106 | cString lastAddrM; 107 | cString lastParamM; 108 | cString tnrParamM; 109 | int streamPortM; 110 | cSatipTunerServer currentServerM; 111 | cSatipTunerServer nextServerM; 112 | cMutex mutexM; 113 | cTimeMs reConnectM; 114 | cTimeMs keepAliveM; 115 | cTimeMs statusUpdateM; 116 | cTimeMs pidUpdateCacheM; 117 | cTimeMs setupTimeoutM; 118 | cString sessionM; 119 | eTunerState currentStateM; 120 | cVector internalStateM; 121 | cVector externalStateM; 122 | int timeoutM; 123 | bool hasLockM; 124 | double signalStrengthDBmM; 125 | int signalStrengthM; 126 | int signalQualityM; 127 | int frontendIdM; 128 | int streamIdM; 129 | int pmtPidM; 130 | cSatipPid addPidsM; 131 | cSatipPid delPidsM; 132 | cSatipPid pidsM; 133 | 134 | bool Connect(void); 135 | bool Disconnect(void); 136 | bool Receive(void); 137 | bool KeepAlive(bool forceP = false); 138 | bool ReadReceptionStatus(bool forceP = false); 139 | bool UpdatePids(bool forceP = false); 140 | void UpdateCurrentState(void); 141 | bool StateRequested(void); 142 | bool RequestState(eTunerState stateP, eStateMode modeP); 143 | const char *StateModeString(eStateMode modeP); 144 | const char *TunerStateString(eTunerState stateP); 145 | cString GetBaseUrl(const char *addressP, const int portP); 146 | 147 | protected: 148 | virtual void Action(void); 149 | 150 | public: 151 | cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP); 152 | virtual ~cSatipTuner(); 153 | bool IsTuned(void) const { return (currentStateM >= tsTuned); } 154 | bool SetSource(cSatipServer *serverP, const int transponderP, const char *parameterP, const int indexP); 155 | bool SetPid(int pidP, int typeP, bool onP); 156 | bool Open(void); 157 | bool Close(void); 158 | int FrontendId(void); 159 | int SignalStrength(void); 160 | double SignalStrengthDBm(void); 161 | int SignalQuality(void); 162 | bool HasLock(void); 163 | cString GetSignalStatus(void); 164 | cString GetInformation(void); 165 | 166 | // for internal tuner interface 167 | public: 168 | virtual void ProcessVideoData(u_char *bufferP, int lengthP); 169 | virtual void ProcessApplicationData(u_char *bufferP, int lengthP); 170 | virtual void ProcessRtpData(u_char *bufferP, int lengthP); 171 | virtual void ProcessRtcpData(u_char *bufferP, int lengthP); 172 | virtual void SetStreamId(int streamIdP); 173 | virtual void SetSessionTimeout(const char *sessionP, int timeoutP); 174 | virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP); 175 | virtual int GetId(void); 176 | }; 177 | 178 | #endif // __SATIP_TUNER_H 179 | -------------------------------------------------------------------------------- /tunerif.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tunerif.h: SAT>IP plugin for the Video Disk Recorder 3 | * 4 | * See the README file for copyright information and how to reach the author. 5 | * 6 | */ 7 | 8 | #ifndef __SATIP_TUNERIF_H 9 | #define __SATIP_TUNERIF_H 10 | 11 | class cSatipTunerIf { 12 | public: 13 | cSatipTunerIf() {} 14 | virtual ~cSatipTunerIf() {} 15 | virtual void ProcessVideoData(u_char *bufferP, int lengthP) = 0; 16 | virtual void ProcessApplicationData(u_char *bufferP, int lengthP) = 0; 17 | virtual void ProcessRtpData(u_char *bufferP, int lengthP) = 0; 18 | virtual void ProcessRtcpData(u_char *bufferP, int lengthP) = 0; 19 | virtual void SetStreamId(int streamIdP) = 0; 20 | virtual void SetSessionTimeout(const char *sessionP, int timeoutP) = 0; 21 | virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP) = 0; 22 | virtual int GetId(void) = 0; 23 | 24 | private: 25 | explicit cSatipTunerIf(const cSatipTunerIf&); 26 | cSatipTunerIf& operator=(const cSatipTunerIf&); 27 | }; 28 | 29 | #endif // __SATIP_TUNERIF_H 30 | --------------------------------------------------------------------------------