├── .gitignore ├── 7f764937-d0d7-11e1-9b23-00059e9651fd.xml ├── LICENSE ├── README.md ├── conf ├── discoveryServer.config ├── rtspServer.config ├── rtspServer.config~ ├── rtspServer2.config └── rtspServer2.config~ ├── discoveryServer.py ├── docs ├── Documentation.docx ├── README.md ├── conclusions-reference.md ├── discovery-sm.md ├── dvblast-overview.md ├── future-work.md ├── images │ ├── figure1.png │ ├── figure2.png │ ├── figure3.png │ ├── figure4.png │ └── figure5.png ├── results-utilization.md ├── rtp_udp-http_tcp.md ├── rtsp-sm.md ├── sat2ip-overview.md └── t2ip.md ├── dvb-t ├── allFrequencies.txt ├── allFrequencies.txt~ ├── pid474000000.cfg ├── pid498000000.cfg ├── pid522000000.cfg ├── pid578000000.cfg ├── pid618000000.cfg ├── pid666000000.cfg ├── pid674000000.cfg ├── pid706000000.cfg ├── pid730000000.cfg ├── pid746000000.cfg └── pid770000000.cfg ├── dvb-usb-af9015.fw ├── dvb-usb-dib0700-1.20.fw ├── install ├── logs ├── discoveryServer.log ├── resources.log ├── rtspServer.log ├── rtspServerWorker.log ├── scanning.log ├── scanning.log~ └── t2IP.log ├── netInterfaceStatus.py ├── resources.py ├── rtspServer.py ├── rtspServerWorker.py ├── scanning.py ├── t2IP.py └── t2IP.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /7f764937-d0d7-11e1-9b23-00059e9651fd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1 5 | 1 6 | 7 | 8 | urn:ses-com:device:SatIPServer:1 9 | EBU T2IP Converter 10 | EBU 11 | TSS400 12 | uuid:7f764937-d0d7-11e1-9b23-00059e9651fd 13 | http://www.triax.fr/ 14 | 15 | 16 | image/png 17 | 120 18 | 120 19 | 24 20 | 21 | http://192.168.2.61:80/SAT_IP_icon120x120.png 22 | 23 | 24 | 25 | image/jpeg 26 | 120 27 | 120 28 | 24 29 | 30 | http://192.168.2.61:80/SAT_IP_icon120x120.jpg 31 | 32 | 33 | 34 | image/png 35 | 48 36 | 48 37 | 24 38 | 39 | http://192.168.2.61:80/SAT_IP_icon48x48.png 40 | 41 | 42 | 43 | image/jpeg 44 | 48 45 | 48 46 | 24 47 | 48 | http://192.168.2.61:80/SAT_IP_icon48x48.jpg 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, European Broadcasting Union 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of cpa-ios nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DTT 2 IP 2 | 3 | Broadcast to IP conversion for Wifi indoor coverage 4 | 5 | The goal of the this project is to have a full working solution in order to provide terrestrial television, for any indoor Wi-Fi network, that can be access on any portable device. In order to achieve this we have set a few requirements in order to have a standardized solution that can fulfill any demand from the user perspective. 6 | These are the following: 7 | * 2 or more DVB-T tuners 8 | * Good image quality and response 9 | * Interoperability with all devices (Android, iOS, etc.) 10 | * Does not block your Wi-Fi for TV only 11 | * Plug and play and easy to use 12 | * Multiple user capabilities for watching different programs 13 | * Interoperability with other SAT>IP servers 14 | * EPG / Subtitles / HbbTV 15 | * Wireless connectivity to our network 16 | * Build-in storage / usb ports / network storage 17 | * Recording capabilities 18 | * Be accessible from any device that haves a browser 19 | 20 | ## Documentation 21 | 22 | 1. [Introduction](docs/README.md#introduction) 23 | 2. [Goal](docs/README.md#goal) 24 | 3. [Sat>IP overview](docs/sat2ip-overview.md) 25 | 4. [Discovery state machine](docs/discovery-sm.md) 26 | 5. [RTSP state machine](docs/rtsp-sm.md) 27 | 6. [RTP/UDP vs. HTTP/TCP](docs/rtp_udp-http_tcp.md) 28 | 7. [DVBlast overview](docs/dvblast-overview.md) 29 | 8. [T2IP Server implementation](docs/t2ip.md) 30 | 9. [Results and utilization](docs/results-utilization.md) 31 | 10. [Future work](docs/future-work.md) 32 | 11. [Conclusion and Reference](docs/conclusions-reference.md) 33 | 34 | ## Contributors 35 | 36 | * [Alexandru Munteanu](@alexmnt) (EBU) 37 | 38 | Contact: [Walid Sami](sami@ebu.ch) 39 | 40 | ## Copyright & license 41 | 42 | Copyright (c) 2015, EBU-UER Technology & Innovation 43 | 44 | The code is under BSD (3-Clause) License. (see LICENSE) 45 | -------------------------------------------------------------------------------- /conf/discoveryServer.config: -------------------------------------------------------------------------------- 1 | # Please be carefull when editing this file. 2 | # the paramaters are specify underneath and the syntax is: 3 | # parameter_name' '=' 'value 4 | # and has to have the last line blank 5 | 6 | cacheControl = 1800 7 | location = 7f764937-d0d7-11e1-9b23-00059e9651fd.xml 8 | server = CW/1.0 UPnP/1.1 CWUpnp/1.1 9 | uuid = 7f764937-d0d7-11e1-9b23-00059e9651fd 10 | upnp = rootdevice 11 | urn = ses-com:device:SatIPServer:1 12 | bootId = 981 13 | configId = 2212703 14 | deviceId = 1 15 | httpPort = 80 16 | -------------------------------------------------------------------------------- /conf/rtspServer.config: -------------------------------------------------------------------------------- 1 | # Please be carefull when editing this file. 2 | # The syntax is : 3 | # fakeFrequencydvbtFrequencybandwidthmodulationTypepid (for the moment no bandwith or modulation) 4 | # Use "#" to comment line 5 | 6 | 10729 498000000 1537 7 | 10743 498000000 1538 8 | 10773 498000000 1539 9 | 10788 498000000 1542 10 | 10818 498000000 1543 11 | 10832 578000000 1 12 | 10847 578000000 257 13 | 10862 578000000 258 14 | 10876 578000000 513 15 | 10979 618000000 2817 16 | 11023 618000000 2818 17 | 11038 618000000 2819 18 | 11097 666000000 257 19 | 11156 666000000 260 20 | 11171 666000000 261 21 | 11303 666000000 262 22 | 11318 666000000 282 23 | 11362 666000000 324 24 | 11436 674000000 2050 25 | 11464 706000000 257 26 | 11479 730000000 2561 27 | 11509 730000000 2562 28 | 11538 730000000 2563 29 | 11568 746000000 1025 30 | 11597 746000000 1026 31 | 11627 746000000 1027 32 | 11671 746000000 1028 33 | 11686 746000000 1031 34 | 11720 770000000 1281 35 | 11739 770000000 1282 36 | 11758 770000000 1283 37 | -------------------------------------------------------------------------------- /conf/rtspServer.config~: -------------------------------------------------------------------------------- 1 | # Please be carefull when editing this file. 2 | # The syntax is : 3 | # fakeFrequencydvbtFrequencybandwidthmodulationTypepid (for the moment no bandwith or modulation) 4 | # Use "#" to comment line 5 | 6 | 10729 474000000 513 7 | 10743 474000000 515 8 | 10773 474000000 516 9 | 10788 474000000 517 10 | 10818 474000000 518 11 | 10832 474000000 519 12 | 10847 498000000 1537 13 | 10862 498000000 1538 14 | 10876 498000000 1539 15 | 10979 498000000 1542 16 | 11023 498000000 1543 17 | 11038 522000000 769 18 | 11097 522000000 770 19 | 11156 522000000 771 20 | 11171 522000000 772 21 | 11303 578000000 1 22 | 11318 578000000 257 23 | 11362 578000000 258 24 | 11436 578000000 513 25 | 11464 618000000 2817 26 | 11479 618000000 2818 27 | 11509 618000000 2819 28 | 11538 666000000 257 29 | 11568 666000000 260 30 | 11597 666000000 261 31 | 11627 666000000 262 32 | 11671 666000000 282 33 | 11686 666000000 324 34 | 11720 674000000 2050 35 | 11739 706000000 257 36 | 11758 730000000 2561 37 | 11778 730000000 2562 38 | 11798 730000000 2563 39 | 11817 746000000 1025 40 | 11836 746000000 1026 41 | 11856 746000000 1027 42 | 11876 746000000 1028 43 | 11895 746000000 1031 44 | 11914 770000000 1281 45 | 11934 770000000 1282 46 | 11954 770000000 1283 47 | 10729 474000000 513 48 | 10743 474000000 515 49 | 10773 474000000 516 50 | 10788 474000000 517 51 | 10818 474000000 518 52 | 10832 474000000 519 53 | 10847 498000000 1537 54 | 10862 498000000 1538 55 | 10876 498000000 1539 56 | 10979 498000000 1542 57 | 11023 498000000 1543 58 | 11038 522000000 769 59 | 11097 522000000 770 60 | 11156 522000000 771 61 | 11171 522000000 772 62 | 11303 578000000 1 63 | 11318 578000000 257 64 | 11362 578000000 258 65 | 11436 578000000 513 66 | 11464 618000000 2817 67 | 11479 618000000 2818 68 | 11509 618000000 2819 69 | 11538 666000000 257 70 | 11568 666000000 260 71 | 11597 666000000 261 72 | 11627 666000000 262 73 | 11671 666000000 282 74 | 11686 666000000 324 75 | 11720 674000000 2050 76 | 11739 706000000 257 77 | 11758 730000000 2561 78 | 11778 730000000 2562 79 | 11798 730000000 2563 80 | 11817 746000000 1025 81 | 11836 746000000 1026 82 | 11856 746000000 1027 83 | 11876 746000000 1028 84 | 11895 746000000 1031 85 | 11914 770000000 1281 86 | 11934 770000000 1282 87 | 11954 770000000 1283 88 | -------------------------------------------------------------------------------- /conf/rtspServer2.config: -------------------------------------------------------------------------------- 1 | # Please be carefull when editing this file. 2 | # The syntax is : 3 | # fakeFrequencydvbtFrequencybandwidthmodulationTypepid (for the moment no bandwith or modulation) 4 | # Use "" to comment line 5 | 6 | 10729 770000000 1282 7 | 10743 770000000 1282 8 | 10773 770000000 1282 9 | 10788 770000000 1282 10 | 10818 770000000 1282 11 | 10832 770000000 1282 12 | 10847 770000000 1282 13 | 10862 770000000 1282 14 | 10876 770000000 1282 15 | 10979 770000000 1282 16 | 11023 770000000 1282 17 | 11038 770000000 1282 18 | 11097 770000000 1282 19 | 11156 770000000 1282 20 | 11171 770000000 1282 21 | 11303 770000000 1282 22 | 11318 770000000 1282 23 | 11362 770000000 1282 24 | 11436 770000000 1282 25 | 11464 770000000 1282 26 | 11479 770000000 1282 27 | 11509 770000000 1282 28 | 11538 770000000 1282 29 | 11568 770000000 1282 30 | 11597 770000000 1282 31 | 11627 770000000 1282 32 | 11671 770000000 1282 33 | 11686 770000000 1282 34 | 11720 770000000 1282 35 | 11739 770000000 1282 36 | 11758 770000000 1282 37 | 11778 770000000 1282 38 | 11798 770000000 1282 39 | 11817 770000000 1282 40 | 11836 770000000 1282 41 | 11856 770000000 1282 42 | 11876 770000000 1282 43 | 11895 770000000 1282 44 | 11914 770000000 1282 45 | 11934 770000000 1282 46 | 11954 770000000 1282 47 | -------------------------------------------------------------------------------- /conf/rtspServer2.config~: -------------------------------------------------------------------------------- 1 | # Please be carefull when editing this file. 2 | # The syntax is : 3 | # fakeFrequencydvbtFrequencybandwidthmodulationTypepid (for the moment no bandwith or modulation) 4 | # Use "#" to comment line 5 | 6 | 10729 474000000 513 7 | 10743 474000000 515 8 | 10773 474000000 516 9 | 10788 474000000 517 10 | 10818 474000000 518 11 | 10832 474000000 519 12 | 10847 498000000 1537 13 | 10862 498000000 1538 14 | 10876 498000000 1539 15 | 10979 498000000 1542 16 | 11023 498000000 1543 17 | 11038 522000000 769 18 | 11097 522000000 770 19 | 11156 522000000 771 20 | 11171 522000000 772 21 | 11303 578000000 1 22 | 11318 578000000 257 23 | 11362 578000000 258 24 | 11436 578000000 513 25 | 11464 618000000 2817 26 | 11479 618000000 2818 27 | 11509 618000000 2819 28 | 11538 666000000 257 29 | 11568 666000000 260 30 | 11597 666000000 261 31 | 11627 666000000 262 32 | 11671 666000000 282 33 | 11686 666000000 324 34 | 11720 674000000 2050 35 | 11739 706000000 257 36 | 11758 730000000 2561 37 | 11778 730000000 2562 38 | 11798 730000000 2563 39 | 11817 746000000 1025 40 | 11836 746000000 1026 41 | 11856 746000000 1027 42 | 11876 746000000 1028 43 | 11895 746000000 1031 44 | 11914 770000000 1281 45 | 11934 770000000 1282 46 | 11954 770000000 1283 47 | -------------------------------------------------------------------------------- /discoveryServer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Discovery state machine 4 | # SSDP protocol 5 | 6 | import sys, re, os, random 7 | import threading, socket, struct, time, calendar 8 | from netInterfaceStatus import getServerIP 9 | 10 | from datetime import date, datetime 11 | 12 | global SSDP_TERMINATE 13 | global deviceIdOk 14 | global ssdpAddr, ssdpPort, serverIP 15 | global paramDict 16 | global NT, USN, st 17 | global fLog 18 | 19 | 20 | paramDict = {} 21 | f = open("conf/discoveryServer.config", 'r') 22 | lines = f.readlines() 23 | for i in range(5, len(lines)): 24 | line = lines[i] 25 | lineArray = line.split('=') 26 | lineArray[0] = lineArray[0][:-1] 27 | lineArray[1] = lineArray[1][1:-1] 28 | paramDict[lineArray[0]] = lineArray[1] 29 | f.close() 30 | SSDP_TERMINATE = 0 31 | 32 | deviceIdOk = False 33 | 34 | ssdpAddr = '239.255.255.250' 35 | ssdpPort = 1900 36 | 37 | serverIP = getServerIP() 38 | # Make sure that rtspServer.log file is clean 39 | fLog = open('logs/discoveryServer.log', 'w') 40 | fLog.write("Info discoveryServer: ipAddrServer = " + serverIP + '\n') 41 | 42 | nt1 = 'upnp:' + paramDict['upnp'] 43 | nt2 = 'uuid:' + paramDict['uuid'] 44 | nt3 = 'urn:' + paramDict['urn'] 45 | NT = [nt1, nt2, nt3] 46 | 47 | usn1 = 'uuid:' + paramDict['uuid'] + '::upnp:' + paramDict['upnp'] 48 | usn2 = 'uuid:' + paramDict['uuid'] 49 | usn3 = 'uuid:' + paramDict['uuid'] + '::urn:' + paramDict['urn'] 50 | USN = [usn1, usn2, usn3] 51 | 52 | # bootId = 981 53 | # configId = 2212703 54 | # deviceId = 1 55 | st = 'urn:' + paramDict['urn'] 56 | # To Do make configuration file 57 | 58 | def ms_ok(toClient): 59 | # MS_OK message is used to inform the client about the presents of the DTT2IP / SAT>IP server on the network 60 | # or to inform the other DTT2IP / SAT>IP servers that M-SEARCH message has been correctly received 61 | myDate = date.today() 62 | currentTime = datetime.now().time() 63 | if myDate.day < 10: 64 | dateStr = calendar.day_name[myDate.weekday()] + ' ' + str(myDate.weekday()) + ' ' + calendar.month_name[myDate.month] + ' ' + str(myDate.year) + ' ' + currentTime.isoformat()[:-7] + ' ' + 'GMT' 65 | else: 66 | dateStr = calendar.day_name[myDate.weekday()] + ' 0' + str(myDate.weekday()) + ' ' + calendar.month_name[myDate.month] + ' ' + str(myDate.year) + ' ' + currentTime.isoformat()[:-7] + ' ' + 'GMT' 67 | if toClient: 68 | MS_OK = 'HTTP/1.1 200 OK\r\nCACHE-CONTROL:max-age=%d\r\nDATE:%s\nEXT:\r\nLOCATION:http://%s:%d/%s\r\nSERVER:%s\nST:%s\nUSN:%s\nBOOTID.UPNP.ORG:%d\r\nCONFIGID.UPNP.ORG:%d\n\r\n' % (int(paramDict['cacheControl']), dateStr, serverIP, int(paramDict['httpPort']), paramDict['location'], paramDict['server'], st, USN[2], int(paramDict['bootId']), int(paramDict['configId'])) 69 | else: 70 | MS_OK = 'HTTP/1.1 200 OK\r\nCACHE-CONTROL:max-age=%d\r\nDATE:%s\nEXT:\r\nLOCATION:http://%s:%d/%s\r\nSERVER:%s\nST:%s\nUSN:%s\nBOOTID.UPNP.ORG:%d\r\nCONFIGID.UPNP.ORG:%d\r\nDEVICEID.SES.COM:%d\r\n\r\n' % (int(paramDict['cacheControl']), dateStr, serverIP, int(paramDict['httpPort']), paramDict['location'], paramDict['server'], st, USN[2], int(paramDict['bootId']), int(paramDict['configId']), int(paramDict['deviceId'])) 71 | 72 | return MS_OK 73 | 74 | def ms_notify_alive(nt, usn): 75 | # MS_NOTIFY_ALIVE is use to inform other DTT2IP / SAT>IP servers about our presents in the network. Used in the DEVICE ID negotiation 76 | MS_NOTIFY_ALIVE = 'NOTIFY * HTTP/1.1\r\nHOST: %s:%d\r\nBOOTID.UPNP.ORG:%d\r\nCONFIGID.UPNP.ORG:%d\r\nCACHE-CONTROL: max-age=%d\r\nLOCATION:http://%s:%d/%s\r\nNT:%s\nNTS:%s\nSERVER:%s\nUSN:%s\nDEVICEID.SES.COM:%d\r\n\r\n' % (ssdpAddr, ssdpPort, int(paramDict['bootId']), int(paramDict['configId']), int(paramDict['cacheControl']), serverIP, int(paramDict['httpPort']), paramDict['location'], nt, 'ssdp:alive', paramDict['server'], usn, int(paramDict['deviceId'])) 77 | return MS_NOTIFY_ALIVE 78 | 79 | def ms_nofity_byebye(nt, usn): 80 | # MS_NOTIFY_BYEBYE is use to infrom other servers that we are leaving the network 81 | MS_NOTIFY_BYEBYE = 'NOTIFY * HTTP/1.1\r\nHOST: %s:%d\r\nNT:%s\nNTS:%s\nUSN:%s\nBOOTID.UPNP.ORG:%d\r\nCONFIGID.UPNP.ORG:%d\r\n\r\n' % (ssdpAddr, ssdpPort, nt, 'ssdp:byebye', usn, int(paramDict['bootId']), int(paramDict['configId'])) 82 | return MS_NOTIFY_BYEBYE 83 | 84 | def ms_search(): 85 | # MS_SEARCH is used to inform other DTT2IP / SAT>IP servers that the DEVICE ID that they want to use belongs to us. Used in the DEVICE ID negotiation 86 | MS_SEARCH = 'M-SEARCH * HTTP/1.1\r\nHOST:%s:%d\r\nMAN:"ssdp-discover"ST:%s\nUSER-AGENT:%s\nDEVICEID.SES.COM:%d' % (serverIP, ssdpPort, st, paramDict['server'], int(paramDict['deviceId'])) 87 | return MS_SEARCH 88 | 89 | def callServerReactor(): 90 | global SSDP_TERMINATE 91 | global fLog 92 | 93 | # Open a multicast socket 94 | fLog.write('Info: Discovery server started\n') 95 | 96 | ssdpMulticastSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 97 | ssdpMulticastSocket.bind((ssdpAddr, ssdpPort)) 98 | 99 | group = socket.inet_aton(ssdpAddr) 100 | mreq = struct.pack('4sL', group, socket.INADDR_ANY) 101 | ssdpMulticastSocket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) 102 | ssdpMulticastSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 103 | 104 | # While look until script is terminated 105 | while (not SSDP_TERMINATE): 106 | # Wait to receive multicast messages either from client or from new servers that have joined the network 107 | datagram, address = ssdpMulticastSocket.recvfrom(1024) 108 | datagram_array = datagram.rsplit('\r\n') 109 | 110 | try: 111 | first_line = datagram_array[0] 112 | # See if the multicast messages are from the clients/servers 113 | matchMSearch = re.search(r'M-SEARCH',first_line) 114 | matchNotify = re.search(r'NOTIFY',first_line) 115 | 116 | if matchMSearch: 117 | # If M-SEARCH message from client, then process it and respond to it with a unicast message 118 | match2 = re.search(r'ses-com',datagram) 119 | if match2: 120 | # fLog.write("Info: client = ip " + address[0] + ", port " + address[1] + "\n") 121 | fLog.write("Info: client \n") 122 | toClient = True 123 | ssdpMulticastSocket.sendto(ms_ok(toClient), (address[0], address[1])) 124 | 125 | if matchNotify: 126 | # If NOTIFY message from server, then process it and see it is another DTT2IP / SAT>IP server 127 | matchSES = re.search(r'DEVICEID.SES.COM:([\w]+)',datagram) 128 | if matchSES: 129 | # If new DTT2IP / SAT>IP server that has join the network then respond to it with a unicast message 130 | # informing it that DEVICE ID is ours, else if this is an old DTT2IP / SAT>IP server do not do anything 131 | if int(matchSES.group(1)) == int(paramDict['deviceId']): 132 | ssdpMulticastSocket.sendto(ms_search(), (address[0], address[1])) 133 | fLog.write("Info: MS_SEARCH\n") 134 | except: 135 | fLog.write("Info: Something went wrong\n") 136 | ssdpMulticastSocket.close() 137 | 138 | def callClientReactor(): 139 | global SSDP_TERMINATE 140 | global deviceIdOk 141 | global fLog 142 | 143 | # Open a unicast socket 144 | fLog.write('Info: Device ID negotion started\n') 145 | 146 | ssdpUnicastSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 147 | ssdpUnicastSocket.bind((serverIP, ssdpPort)) 148 | ssdpUnicastSocket.settimeout(5.0) 149 | 150 | # While look until script is terminated 151 | while (not SSDP_TERMINATE): 152 | # DEVICE ID negotiation loop, escape only when we have valid DEVICE ID 153 | while (not deviceIdOk): 154 | # Send the first 3 SSDP NOTIFY messages 155 | for i in range(3): 156 | paramDict['bootId'] = int(paramDict['bootId']) + 1 157 | ssdpUnicastSocket.sendto(ms_notify_alive(NT[i], USN[i]), (ssdpAddr, ssdpPort)) 158 | fLog.write("Info: MS_NOTIFY_ALIVE\n") 159 | try: 160 | # See if DEVICE ID is free, by waiting for a message or a timeout of 5 seconds 161 | datagram, address = ssdpUnicastSocket.recvfrom(1024) 162 | datagram_array = datagram.rsplit('\r\n') 163 | 164 | try: 165 | # Process the message received 166 | first_line = datagram_array[0] 167 | matchMSearch = re.search(r'M-SEARCH',first_line) 168 | 169 | if matchMSearch: 170 | # See if somebody else is using this ID 171 | matchSES = re.search(r'DEVICEID.SES.COM:([\w]+)',datagram) 172 | if matchSES: 173 | if int(matchSES.group(1)) == int(paramDict['deviceId']): 174 | # This DEVICE ID is used an we have to annouce that we are letting it go 175 | # by sending a MS_OK message to the other server (i.e toClient = False) 176 | # and to the hole network MS_NOTIFY_BYEBYE mesasge. 177 | toClient = False 178 | ssdpUnicastSocket.sendto(ms_ok(toClient), (address[0], address[1])) 179 | fLog.write("Info: MS_OK\n") 180 | 181 | for i in range(3): 182 | ssdpUnicastSocket.sendto(ms_nofity_byebye(NT[i], USN[i]), (ssdpAddr, ssdpPort)) 183 | fLog.write("Info: MS_NOTIFY_BYEBYE\n") 184 | # We have to increase the DEVICE ID 185 | paramDict['deviceId'] = int(paramDict['deviceId']) + 1 186 | except: 187 | fLog.write('Info: Something went wrong\n') 188 | 189 | except: 190 | # Change deviceIdOk to True only when we timeout (5.0 seconds) 191 | fLog.write("Info: DEVICE ID\n") 192 | deviceIdOk = True 193 | # We have obtain out valid DEVICE ID, we have to maintain it valid on the network by sending 194 | # at pseudo random periods 3 MS_NOTIFY_ALIVE messages. The pseudo random interval is between [0, cacheControl/2]. 195 | # This guarantees that announcement set is repeated at least twice before it expires. 196 | fLog.write("Info: Device ID negotiation done. Sleep and send NOTIFY later\n") 197 | time.sleep(random.randint(0, int(paramDict['cacheControl'])/2)) 198 | 199 | for i in range(3): 200 | paramDict['bootId'] = int(paramDict['bootId']) + 1 201 | ssdpUnicastSocket.sendto(ms_notify_alive(NT[i], USN[i]), (ssdpAddr, ssdpPort)) 202 | fLog.write("Info: MS_NOTIFY_ALIVE\n") 203 | ssdpUnicastSocket.close() 204 | 205 | def discoveryServer(): 206 | global fLog 207 | global deviceIdOk 208 | 209 | # DEVICE ID negotiation thread ( server <---> server communications ) 210 | t1 = threading.Thread(target=callClientReactor) 211 | t1.daemon = True 212 | t1.start() 213 | # Wait for DEVICE negotiation to finish then start the Discovery protocol in order for the clients to connect to 214 | while not deviceIdOk: 215 | time.sleep(1) 216 | # DISCOVERY thread for the client applications ( server <---> client communications) 217 | t2 = threading.Thread(target=callServerReactor) 218 | t2.daemon = True 219 | t2.start() 220 | 221 | # Keep threads alive until KeyboardInterrupt 222 | try: 223 | while t1.is_alive() and t2.is_alive(): 224 | t1.join(timeout=1.0) 225 | t2.join(timeout=1.0) 226 | except (KeyboardInterrupt, SystemExit): 227 | fLog.close() 228 | SSDP_TERMINATE = 1 229 | 230 | 231 | if __name__ == "__main__": 232 | discoveryServer() 233 | 234 | 235 | -------------------------------------------------------------------------------- /docs/Documentation.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebu/dtt2ip/b6ee6d77b60edbf3fed34f9d43822aa16499cc76/docs/Documentation.docx -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # DTT2IP 2 | 3 | ## Table of content 4 | 5 | 1. [Introduction](#introduction) 6 | 2. [Goal](#goal) 7 | 3. [Sat>IP overview](sat2ip-overview.md) 8 | 4. [Discovery state machine](discovery-sm.md) 9 | 5. [RTSP state machine](rtsp-sm.md) 10 | 6. [RTP/UDP vs. HTTP/TCP](rtp_udp-http_tcp.md) 11 | 7. [DVBlast overview](dvblast-overview.md) 12 | 8. [T2IP Server implementation](t2ip.md) 13 | 9. [Results and utilization](results-utilization.md) 14 | 10. [Future work](future-work.md) 15 | 11. [Conclusion and Reference](conclusions-reference.md) 16 | 17 | 18 | ## Introduction 19 | 20 | In this paper we try to explain the concept of broadcasting over Wi-Fi networks. We cover the basic knowledge regarding the protocols used, SSDP, RTP, RTSP and the existing technologies and solutions. The following chapters will be dedicated to a better understanding of the necessary steps taken in our implementation. 21 | In a nutshell we have designed a server, from two state machines: the first one handles the discovery by other clients and servers, and the other handles the RTP video streaming request. 22 | 23 | 24 | ## Goal 25 | 26 | The goal of the this project is to have a full working solution in order to provide terrestrial television, for any indoor Wi-Fi network, that can be access on any portable device. 27 | In order to achieve this we have set a few requirements in order to have a standardized solution that can fulfill any demand from the user perspective. 28 | These are the following: 29 | • 2 or more DVB-T tuners 30 | • Good image quality and response 31 | • Interoperability with all devices (Android, iOS, etc.) 32 | • Does not block your Wi-Fi for TV only 33 | • Plug and play and easy to use 34 | • Multiple user capabilities for watching different programs 35 | • Interoperability with other SAT>IP servers 36 | • EPG / Subtitles / HbbTV 37 | • Wireless connectivity to our network 38 | • Build-in storage / usb ports / network storage 39 | • Recording capabilities 40 | • Be accessible from any device that haves a browser 41 | Before we committing to the new implementation, at the beginning we have investigated the existing ones, that a regular user can have access. Without losing objectivity, and after technical and not technical debates we have reached the conclusion that the preexisting solution does not fully convince us, and that is better to have our own EBU software. However our research, has paid of with the interesting concept of SAT>IP, that will be explained in the following chapter. 42 | 43 | -------------------------------------------------------------------------------- /docs/conclusions-reference.md: -------------------------------------------------------------------------------- 1 | # Conclusions and Reference 2 | 3 | ### Index 4 | 1. [Conclusions](#conclusions) 5 | 2. [Reference](#reference) 6 | 7 | ###### Conclusions 8 | We have manage to create, based on the Sat>IP standard, our own server for converting DVB-T RF signal to IP packets and stream it through an indoor Wi-Fi network. Being only a software implementation, and using common and well-used development environment, we have deployed it easily on different hardware platforms. Another feature that we have accomplished is the universality for the client application, which means that every user can have a freedom of choice for displaying the broadcast channels. 9 | 10 | ###### Reference 11 | 1. 12 | ##### [Back to Table of content](README.md) 13 | -------------------------------------------------------------------------------- /docs/discovery-sm.md: -------------------------------------------------------------------------------- 1 | # Discovery state machine 2 | 3 | During the discovery phase SAT>IP servers advertise their presence to other SAT>IP servers and clients. When joining a network, SAT>IP clients search the network for available SAT>IP servers. 4 | Discovery in SAT>IP relies on the Simple Service Description Protocol (SSDP) [11] as specified in the UPnP Device Architecture 1.1 [1]. 5 | As a minimum: 6 | - a SAT>IP server is a UPnP Device and a UPnP Control Point, 
 7 | - a SAT>IP client is a UPnP Control Point. 
 8 | 9 | SAT>IP servers joining a network multicast three different NOTIFY ssdp:alive messages to the SSDP address 239.255.255.250 port 1900. This is a requirement for UPnP root devices according to the UPnP Device Architecture 1.1 [1]. 10 | 11 | A SAT>IP server present on the network has to re-announce itself on a regular basis as described under CACHE-CONTROL above. 12 | A SAT>IP server leaving the network needs to signal its departure by sending three different NOTIFY messages with the NTS value ssdp:byebye. 13 | Please note that the ssdp:byebye messages should not include the CACHE-CONTROL, LOCATION, SERVER and DEVICEID.SES.COM headers. An example of such ssdp:byebye messages is shown in Section 3.3.3. 14 | A SAT>IP server changing the network e.g. when passing from an Auto-IP network to a network with a DHCP assigned address shall signal its departure from one network by sending three NOTIFY messages with the NTS value ssdp:byebye on that network and shall announce its presence on the new network by sending three NOTIFY ssdp:alive messages. 15 | SAT>IP clients (being at a minimum only UPnP Control Points) do not announce their presence. For this reason, a client leaving the network is not detectable at this level. The SAT>IP protocol however implements RTSP and IGMP which permit to detect the presence or absence of a client (RTSP session timeout, IGMP membership queries). 16 | ##### [Back to Table of content](README.md) 17 | -------------------------------------------------------------------------------- /docs/dvblast-overview.md: -------------------------------------------------------------------------------- 1 | # Dvblast overview 2 | 3 | DVBlast is written to be the core of a custom IRD, CID, or ASI gateway, based on a PC with a Linux-supported card. It is very lightweight and stable, designed for 24/7 operation. 4 | DVBlast does not do any kind of processing on the elementary streams, such as transcoding, PID remapping or remultiplexing. If you were looking for these features, switch to VLC. It does not stream from plain files (have a look at multicat instead). 5 | DVBlast supports several input methods: 6 | linux-dvb-supported cards (DVB-S, DVB-S2, DVB-C, DVB-T...) with or without CI interface 7 | DVB-ASI cards (from Computer Modules) 8 | UDP or RTP, unicast or multicast, streams carrying a transport stream 9 | 10 | It outputs one or several RTP streams carrying transport streams with: 11 | hardware or software PID filtering 12 | PID-based or service-based demultiplexing 13 | optional descrambling via CAM device 14 | optional DVB tables 15 | ##### [Back to Table of content](README.md) 16 | -------------------------------------------------------------------------------- /docs/future-work.md: -------------------------------------------------------------------------------- 1 | # Future work 2 | 3 | From the server perspective they may exist improvements all the time, as well as maintaining the code up to date with the new client software requirements. The server must have a configuration page where you can request new scans, configure some parameter, however it must be keeps as simple as possible. This page must provide some real-time and relevant information regarding the status of the server. 4 | The second possible future work must be in the direction of creating our own client software that will run on the entire mobile device, this including Windows 10 phones and tables (by doing this desktops can also have this application as well). This client must provide all the features carried on the transport stream (subtitles, Teletext, HbbTv). Another future implementation can be to provide connectivity to the server through a browser, by using and leveraging MPEG-DASH. As proof of concept we have a basic demo in the “demoTestLiveTools.tar.gz” package. Unpack the compressed file, and run as root the “demoTestLiveTools.py” script. This will install the necessary tools that will be used and create and “index.html” page, that can be access directly from your host. This will display a basic video player, which will start playing off the air the broadcast channel. 5 | ##### [Back to Table of content](README.md) 6 | -------------------------------------------------------------------------------- /docs/images/figure1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebu/dtt2ip/b6ee6d77b60edbf3fed34f9d43822aa16499cc76/docs/images/figure1.png -------------------------------------------------------------------------------- /docs/images/figure2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebu/dtt2ip/b6ee6d77b60edbf3fed34f9d43822aa16499cc76/docs/images/figure2.png -------------------------------------------------------------------------------- /docs/images/figure3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebu/dtt2ip/b6ee6d77b60edbf3fed34f9d43822aa16499cc76/docs/images/figure3.png -------------------------------------------------------------------------------- /docs/images/figure4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebu/dtt2ip/b6ee6d77b60edbf3fed34f9d43822aa16499cc76/docs/images/figure4.png -------------------------------------------------------------------------------- /docs/images/figure5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebu/dtt2ip/b6ee6d77b60edbf3fed34f9d43822aa16499cc76/docs/images/figure5.png -------------------------------------------------------------------------------- /docs/results-utilization.md: -------------------------------------------------------------------------------- 1 | # Results and utilizations 2 | 3 | ### Index 4 | 1. [Raspberry Pi installation](#raspberry-pi) 5 | 2. [Synology installation](#synology-nas) 6 | 3. [Synology installation easy](#synology-nas-easy) 7 | 8 | We have implemented the application to run on Raspberry Pi and Synology NAS with good results. The real-time scanning of the available frequencies was managed for multiple users, as well as tuning to different channels at the same time. The image quality was depending most of the time on the received RF signal, occupying only 4Mbps of the bandwidth. From our observations the multicasting one channel to the network was possible, however with poor playback quality, this problem being related to the concept of multicast. In order for every connected client in the network receive the multicast packets; the channel must have a low transmission rate., which does not satisfies the our minimum transmission rate per channel. 9 | Regarding the HD channels, we can receive them as well, with some playback degradation. The only client application, being able to display HD channel is “tivizen”. Another interesting remark concerning the client software, is that “Sat>IP” does support only one server per WiFi, where as with “tivizen” you could switch between them. “Sat>IP” offers a better user experience, with more features like: EPG, subtitles, and Teletext, whereas “tivizen” can only decode the EPG. 10 | Depending on the platform that you want to run our application you must follow the next steps. 11 | 12 | ###### Raspberry Pi 13 | Install Raspian image on the SD flash card, by following these steps: 14 | 15 | 1. Download the Raspian image from to your computer from [here](https://www.raspberrypi.org/downloads/raspbian/) (e.g. “2015-05-05-raspbian-wheezy.img”) 16 | 2. Insert the SD flash into your computer (Mac). 17 | 3. Open a terminal window. 18 | 4. Execute: 19 | - “# diskutil list” to list the available disk, and to get the name of the SD flash on which we will pe loading the image (“2015-05-05-raspbian-wheezy.img”) 20 | - “# diskutil unmountDisk /dev/disk “ to unmounts the SD flash, where must be replace with the number corresponding to your SD flash. 21 | - “# sudo dd bs=1m if=/2015-05-05-raspbian-wheezy.img of=/dev/rdisk” to load the image, where must be replaced with the path to place where you downloaded the Raspian image. 22 | 5. Done. You now have and SD flash with an Raspian image on it. 23 | 24 | Place the SD flash into the Raspberry Pi, and boot it up with an Internet connection. The default login to the Raspberry Pi is: 25 | - Username: pi 26 | - Password: raspberry 27 | Change to the directory you want to have the application installed; execute the following commands and login with our credential: 28 | “$ git clone -b develop https://github.com/ebu/dtt2ip.git” 29 | “$ cd dtt2ip/” 30 | “$ sudo ./raspberryInstall” 31 | 32 | This will take care of all the packages need, and make all the necessary changes in order to have a fully working t2IP server, the next time you boot the Raspberry Pi. 33 | Restart the Raspberry Pi and wait for 15-20 min in order for the first scan to finish, before connecting any mobile client. 34 | “$ sudo reboot” to restart the Raspberry Pi 35 | 36 | 37 | ###### Synology NAS 38 | Install on your Synology from the Package Center application, Debian Chroot by following the steps: 39 | 1. Go to Package Center and in the Community tab add the following URL: 40 | https://synocommunity.com/packages 41 | 2. Select option install from different third party software 42 | 3. Install Debian Chroot 43 | 4. Make sure Debian Chroot application is running after installation 44 | 45 | Install Git from the Package Center and get the following repository and place it in the location you want to have the t2IP server installed (e.g. volume1/yourDir), by following the setps: 46 | 1. Open a terminal window on your computer (Mac): 47 | 2. SSH to the Synology as root: 48 | - “# ssh root@ip_address_synology” 49 | - “> cd /volume1/yourDir/”, this will change to the directory you have placed the t2IP 50 | server application. 51 | - “> git clone -b develop https://github.com/ebu/dtt2ip.git” 52 | - “> cd dtt2ip/” 53 | - “> ./synologyInstall”, this will run the installation script 54 | 55 | This will take care of all the packages need, and make all the necessary changes in order to have a fully working t2IP server, the next time you start the Debian Chroot application from Synology. 56 | Stop and Start the Debian Chroot application from the Package Center app, and wait for 15-20 min for the first scan to finish before connecting any mobile client. 57 | 58 | ###### Synology NAS easy 59 | ###### [Back to Table of content](README.md) 60 | -------------------------------------------------------------------------------- /docs/rtp_udp-http_tcp.md: -------------------------------------------------------------------------------- 1 | # RTP/UDP vs HTTP/TCP 2 | 3 | The Real Time Transport Protocol (RTP) has been around for a long time and is often used for streaming. It's defined by IETF RFC 3550. It's a transport protocol which is built on UDP and designed specifically for real-time transfers. It's possible but unusual to use RTP with TCP. Although it sits on top of UDP (or TCP), it's still considered part of the transport layer. It's closely associated with the Real Time Control Protocol (RTCP), which operates at the session layer. The primary function of RTCP is "to provide feedback on the quality of the data distribution," allowing actions such as adjusting the data rate. 4 | Some other protocols are typically used with RTP but aren't tightly coupled to it. The Real Time Streaming Protocol (RTSP), defined by IETF RFC 2326, is a presentation-layer protocol that is described as a "network remote control." It resembles HTTP in some ways, and it carries requests to initiate activities such as playing, pausing, and recording. The Resource Reservation Protocol, with the strained abbreviation RSVP and a spec at RFC 2205, operates at the transport level though it's used in setting up sessions. The protocol stack of RTP, RTCP, and RTSP is sometimes referred to as "RTSP." 5 | RTP, RTCP, and RTSP all operate on different ports. Usually when RTP is on port N, RTCP is on port N+1. 6 | An RTP session may contain multiple streams to be combined at the receiver's end; for example, audio and video may be on separate channels. 7 | UDP URLs aren't widely supported by browsers, so a plug-in is needed to do RTP/UDP streaming to a browser. Flash is the one that's most commonly used. RTP is also used by standalone players such as RealPlayer, Windows Media Player, and QuickTime Player. 8 | Android and iOS devices don't have RTP-compatible players as delivered. There are various third-party applications, including RealPlayer for Android. 9 | 10 | The new trend in streaming is the use of HTTP with protocols that support adaptive bitrates. This is theoretically a bad fit, as HTTP with TCP/IP is designed for reliable delivery rather than keeping up a steady flow, but with the prevalence of high-speed connections these days it doesn't matter so much. Apple's entry is HTTP Live Streaming, aka HLS or Cupertino streaming. It was developed by Apple for iOS and isn't widely supported outside of Apple's products. Long Tail Video provides a testing page to determine whether a browser supports HLS. Its specification is available as an Internet Draft. The draft contains proprietary material, and publishing derivative works is prohibited. 11 | The only playlist format allowed is M3U Extended (.m3u or .m3u8), but the format of the streams is restricted only by the implementation. 12 | 13 | Adobe HTTP Dynamic Streaming (HDS) is also known as San Jose streaming. Like Apple's HLS, it operates over HTTP. Like RTMP, it's associated with Flash. HTTP is more likely to be allowed through than other protocols, and HDS is less of a kludge than RTMP over HTTP. The technical specs say that Flash is required for playback, so its use is mainly in desktop environments. 14 | 15 | DASH, for Dynamic Streaming over HTTP, is MPEG's offering in the HTTP streaming Babel. DASH's creators insist it's not a protocol but an "enabler," but that claim violates the "looks like a duck" principle. It's specified by ISO/IEC 23009-1:2012. 16 | HTML5 needs to be mentioned here, mostly for what it isn't. HTML5 provides the