Plex DVR on Docker with the Official Xbox One Digital TV Tuner

In the last part of this series we got the Official Xbox One TV Tuner working successfully with Plex on a beta version of Fedora 28.

Last weekend one part of the RAID-1 boot drive array I used for my media server failed, so I took the opportunity to give Fedora 28 a shot as my boot OS with the replacement drive as opposed to imediately repairing the RAID. If this didn’t work out I can still swap some drives around and let the RAID resync. This may still happen, as Fedora is not offically supported on the HP Microserver I run, so I miss out on some of the agents used by the Integrated Lights-Out (iLO) server management interface to report back machine metrics.

As part of this switch I am re-evaluating what I can use Docker for, and so have OS distribution agnostic, scripted, services. Even if I do choose to switch back to CentOS this will not be a waste as there were some software packages which I was already compiling from source due to a lack of availability in CentOS repositories. When Ubuntu move to the 4.16 kernel I will likely switch again, but should have an easier time as I can re-use the configured Docker containers I have already scripted.

So it is now time to get Plex working on Docker with this tuner.

» Continue reading

Plex DVR with the Official Xbox One Digital TV Tuner - The Direct (and working!) Approach

With the recent release of version 4.16 of the linux kernel, the drivers needed to use the Xbox One Tuner are now distributed with the kernel.

At the time of writing, the only mainstream distribution using this version of the kernel is the Fedora 28 beta (due for mainstream release early May).

With this driver now part of the kernel, Plex appears to recognise the tuner as a community supported tuner and functions correctly using it directly. We still need to download and install the “dvb-demod-mn88472-02.fw” firmware file however as without this, while the tuner will be recognised in Plex, scanning for channels will always return zero results.

» Continue reading

Performance of the Java 8 Date APIs

At the weekend I was skimming over the parts of the OCA exam book which are new for Java 8, and the comparison on working with the new java.time APIs versus the previous java.util offerings got me thinking about performance. Recently I had been looking at a bit of code which was creating objects based on an object loaded from a database table with the fields shown below.

    private java.util.Date date;
    private int startHour;
    private int startMinute;
    private int endHour;
    private int endMinute

The date in this object is set to midnight time. Based on this object the code was then making two java.util.Date objects, one for each time on the date. This requires a trip in to a Calendar object to set the time fields, then converting back to a Date. This appeared to be quite an expensive operation when we were executing it tens of thousands of times during the process of a calculation.

For a test, I wrote a simple program which created an object representing today’s date, and then created 20,000 objects based on this including a time. These steps were performed for both the java.time and java.util approaches.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class DateTest {
    
    private static final int ITERATIONS = 20000;
    private final List<Integer> hours;
    private final List<Integer> minutes;
    private final Date midnightToday;
    private final LocalDate today;
    
    public DateTest() {
        /* Initialise lists */
        this.hours = IntStream.range(0, 23).boxed().collect(Collectors.toList());
        this.minutes = IntStream.range(0, 59).boxed().collect(Collectors.toList());
        
        /* Initialise today with the old approach */
        Date date = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        this.midnightToday = cal.getTime();
        
        /* Initialise today with the new approach */
        this.today = LocalDate.now();
    }
    
    
    public void checkNewApproach() {

        List<LocalDateTime> createdObjects = new ArrayList<>();

        while (createdObjects.size() < ITERATIONS) {
            for (int hour : hours) {
                for (int minute : minutes) {
                    if (createdObjects.size() < ITERATIONS) {
                        /* Create the object and add to our list. */
                        createdObjects.add(LocalTime.of(hour, minute).atDate(today));
                    }
                }
            }
        }
    }
    
    public void checkOldApproachDate() {

        List<Date> createdObjects = new ArrayList<>();

        while (createdObjects.size() < ITERATIONS) {
            for (int hour : hours) {
                for (int minute : minutes) {
                    if (createdObjects.size() < ITERATIONS) {
                        /* Create the object */

                        Calendar cal = Calendar.getInstance();
                        cal.setTime(midnightToday);
                        cal.set(Calendar.HOUR, hour);
                        cal.set(Calendar.MINUTE, minute);

                        createdObjects.add(cal.getTime());
                    }
                }
            }
        }
    }
    
    
    public static void main(String[] args) {
        
        /* Create */
        DateTest testObj = new DateTest();
        
        /* Test the new approach */
        long newStartTime = System.currentTimeMillis();    
        testObj.checkNewApproach();
        long newEndTime = System.currentTimeMillis();
        
        /* Test the old approach */
        long oldStartTime = System.currentTimeMillis();
        testObj.checkOldApproachDate();
        long oldEndTime = System.currentTimeMillis();
        
        /* Show the results */
        
        System.out.println(String.format(
                "\t%s\t%s", 
                (newEndTime - newStartTime), 
                (oldEndTime - oldStartTime))); 
    }

}

I compiled the code and ran the test 10 times, just to rule out any blips in system performance.

javac DateTest.java
for i in {1..10}; do echo $i $(java -cp . DateTest); sleep 2s; done

It is a crude test, but the results were quite surprising.

Run java.time (ms) java.util (ms)
1 7 104
2 7 104
3 11 126
4 10 123
5 13 135
6 12 142
7 16 299
8 10 157
9 10 125
10 8 100

I had expected some performance improvement, but not such a large one. I have no intention of getting into the “why” of the performance improvement, but it does look promising for future developments.

Getting Started With Apache Ivy

Introduction

As noted in the introduction to this series, I wanted to learn a bit about how Ivy worked as a dependency management system integrating with Ant.

The logical starting point here is the Ivy Tutorial, but there are many broken areas of the Quick Start page which make it difficult to follow. It also heavily relies on just inspecting the sample code available as part of the Ivy source code, instead of explaining it in any depth as part of the tutorial.

This and the next part of the series will build up a basic project with a REST service using CDI to inject a cache manager, will all of our code as part of the same module.

» Continue reading