├── .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