Feed on
Posts
Comments

In my previous post, I said “I think I’ll elect to forgo a player for an external drive and rip every disk that I might buy.” That thought didn’t last very long. I decided to buy a Sony NSZ-GT1 which contains both a BluRay player and a GoogleTV together. I did this because I finally realized that the Roku that bought was never going to live up to my requirements, especially amid their numerous regressions in firmware updates.

So, I bought a Roku a few months ago after my dad bought one. He got one of the first generation devices, as well as a second. It was able to play his ripped media, with a little coaxing, but the feature that caught both of our attentions was the 1080p playback. I decided to buy a second generation as well, since it had the ability to create third-party apps (they call them channels).

I started to program for the Roku, only to be first struck by the programming language. While it has similarities to several other scripting languages, it is a new programming language. Those out there familiar with the realities in computer science are screaming in the heads how this is a poor decision, but they made it anyway. I was then struck by the complete lack of library availability. Unfortunately, I had allowed myself to accept the premise that I had no choice in the matter and tried my best to plow on. My father and I had designed a Java server, which facilitated transcoding of files to be served to the Roku. I then started to add in the metadata features found in Sapphire to this server. I had browsing working from the device as well as playback initiated from the device. It was starting to look like a replacement for my AppleTV running Sapphire.

Then came the updates. Roku issues a firmware update, which caused numerous problems. The most notable was when one would play an MP3 on the first generation device (streaming a radio station for instance), then later played an MP4 with H.264, the device locked up requiring a reboot. This bug took a month and a half to fix. Additionally, the HLS streaming, which is what’s used to deliver the transcoded data to the device, was suffering from numerous audio dropouts. Supposedly, this bug was fixed in the update that was released today, but I’ve found reports of this bug in the firmware betas dating as far back as May. This means that roku was aware of the regression for 5 months before releasing the firmware. Furthermore, try to report this bug on their forums, and the fanbois descend on you like a coming plague, insisting that nothing is broken, or that a fix is coming and you must be patient. I’ve even seen some do both, even though they are diametrically apposed positions. I then noticed a firmware update on my second generation roku including some of the same regressions.

I’ve had it.

I decided to get something else. When I looked at the list of options, I narrowed my choice down to AndroidTV and GoogleTV. AndroidTV is essentially hardware vendors taking the open sourced Android OS (the versions that are), and putting in on their devices. GoogleTV is the Android OS, with some additional addons including a large host of codec/container support. I went with the latter, so I now had to pick which device. Sony makes a BluRay player and several TVs, and Logitech used to make their Revue. I went with the BluRay player since it was not discontinued and I didn’t want to buy a TV right now. Also, the GoogleTV’s new firmware is based on Android 3.1, and the AndroidTV devices are mostly on 2.2 or 2.3.

When the device arrived, I started doing some tests. It played nearly everything I threw at it without issue. I played everything over http, just giving the built-in VideoView class a URL to play, and it played it. I tested MKV, AVI, MP4, and MKV files. All had no issues. It even played the killa sample, which is something that the roku failed to play. The programming language is far better, since they used Java, and the programming environment actually works instead of the occasional lockup of the device in the debugger from which the roku suffers. It’s also much faster, and stable. My dad found that Amazon was still selling the Revue, so he bought one based on these results. I don’t know what we are going to do with our roku devices. I expect I may finish the Angry Birds levels, then call it failed experiment and box it up.

In short, don’t buy from roku. Buy a GoogleTV instead. Yes, they are more expensive, but you truly get what you pay for here. The programming environment is far superior, which means the apps will be better. The device works, and it appears that Google actually does regression testing. Additionally, Google appears to be ambitious in the devices future. It looks like GoogleTV truly is the route to go. I just wish I had seen it earlier.

BTW, I plan on fully porting Sapphire over to work on the GoogleTV in a client-server relationship. I’m doing this because I plan to allow sharing a single library across multiple devices. I don’t know yet whether I intend to release it to the public. Sometimes it is nice not having to deal with “customer” support. Browsing and playback is done, as well as an importer to read the previous version’s metadata. All that’s left is the metadata importing of new files. Time will tell on where I go with this.

As some of you may know, I’ve ripped every DVD I own and store them on a file server. It’s a lot of space and it took a lot of time, but for my uses, it’s worth it.

I started this because one movie, I don’t remember which one, forced me to wait on FBI warning, another copyright violation warning, the same in French, and a disclaimer. Then it displayed two previews and a lengthy menu before I could hit play. This was followed by another lengthy menu animation, studio logos, and finally the movie. In the whole process, the studio logos and the previews were the only portions I was able to skip, the other screens marked as not skippable on the DVD. Now that I have my DVDs ripped, when I want to watch a movie, I browse my collection on the TV, and play the movie. No warnings, no menus, just the movie. I actually moved 8 months ago, and I have yet to unpack the DVD player.

This past weekend, I was at my parents’ house and I played a few of their BluRay disks. One movie, I think it was Flyboys, spent a considerable amount of time on the loading screen, had large sections of menus/screens that were not skippable, even included a section where it tried to download a trailer. Once the movie started playing, I paused it and to help feed some kitties and give them attention for a few minutes only to return to a custom screen saver of some sort. The movie would not resume. Upon repeating the process, a total of 15 minutes was wasted excluding the time spent with the movie paused.

So now, I seriously question the value of keeping media in these physical formats. I was considering BluRay in the near future, but now I think I’ll elect to forgo a player for an external drive and rip every disk that I might buy. Now I just need to find a good external drive that allows easy ripping. Thoughts?

It’s been a while since I posted here. I’ve been busy with a new job, new house, and a bunch of other things. One of these things was setting up my new file server. This is something that’s been in the works for a long time, as can be seen from the various posts on ZFS. I spent a long time researching this, and finally came up with my solution:

I did consider FreeNAS for a really long time. It is essentially a FreeBSD install with most of the administrative work done for you through a web-based GUI. It hit most of my checkboxes in that it supported ZFS, AFP, Bonjour, and a few others. While this is nice, I found it also to be limiting when one wants to stray off the beaten path. I didn’t want to lose ZFS, but I wanted something where I could tinker. I decided to go with FreeBSD.

One of the first things I tried with FreeBSD, as the topic indicates, is to put the root filesystem on ZFS. I followed an excellent tutorial to start, but decided to make a few modifications:

  • I wanted to put the root filesystem some place other than the root of the pool. Since my large media collection is going to be stored on the same pool, I wanted the ability to selectively snapshot the boot filesystem, and possibly revert it, without affecting the media partition. So, I put the root filesystem on on a sub filesystem of the pool.
  • The trend in disk storage is looking like it will go to 4K sector sizes in the future. ZFS cannot migrate a pool from 512 byte sector sizes to 4K sector sizes without a reformat/restore. I wanted a 4K sector size pool from the start.
  • I wanted to use ZFS swap instead of swap partitions.
  • I was going to spent several iterations getting things right and didn’t want to type on that blasted 12 year old keyboard the same commands over and over.

So, I accomplished this whole task through a series of scripts, that I would modify. If the script did something wrong, I’d destroy the pool and start over. The end result is a simple setup that I decided to share with the world:

  1. Download and burn/image one of the FreeBSD iso images or USB images. I used 8.2, the most recent at the time of this writing, and did the USB image since I had flash drives to spare but no DVD ROM drives.
  2. Boot the machine and enter the recovery mode (Fixit).
  3. Start the networking:
    mkdir /var/db
    dhclient em0
    ln -s /dist/usr/bin /usr/bin
  4. Transfer over the script directory:
    scp -r username@10.0.0.10:Desktop/FreeBSD/\* .
    In this case, 10.0.0.10 is my laptop with sshd running.
  5. Start sshd: ./FreeBSDSSHSetup.sh
  6. ssh into the machine from my laptop and execute: ./FreeBSDInstall.sh
  7. Reboot the server and enjoy.

The FreeBSD directory is available for those who would like to copy my efforts, though they will likely need some modification to suit your needs. The gptzfsboot, pmbr, and zfsloader files came from this site which are modified versions that work with 4K drives. The versions available in 8.2 do not work with 4K sector sizes, but future versions will. My install script

  • Partitions ad8, 10, 12, 14, 16, 18 to contain the boot loader and zpool information (6 SATA drives),
  • Loads kernel modules and sets up a gnop drive with 4K sectors,
  • Creates a raidz2 pool using the gnop drive as one of the drives forcing 4K sectors, exports the pool,
  • Destroys the gnop drive, re-import the pool, which had been forced to 4K sectors,
  • Sets up root filesystem on zroot/root (zroot is the root of the pool, root is the root filesystem, as discussed above), and
  • Performs a standard zroot install, except no swap partition.

I actually added the swap later, which is simply:
zfs create -V 2G zroot/swap
zfs set org.freebsd:swap=on zroot/swap
zfs set checksum=off zroot/swap

And that’s it. I have my 8TB raid running, with 2 drive redundancy, booting off the raid. Setting up AFP and the like requires more tinkering than with FreeNAS, but the instructions are easy to find and would be redundant to list here.

This is the last is a series of blog posts I’m writing on things that Objective-C can learn from Java. The other parts can be found here:
Part 1 (Generics)
Part 2 (Abstract Classes)
Part 3 (Single Source File)
Part 4 (Namespace)

For one who has programmed in other object oriented languages, Objective-C stands out with its complete lack of namespace. As a result, classes have a prefix, such as Apple’s common NS and UI prefixes. On the mac side of things, every class under the sun seemed to start with NS, such as NSString, and confusion is added when on the iOS side, several classes start with UI, such as UIView. This is due to the fact that without a concept of namespace, Objective-C cannot have two classes with the same name, regardless of whether the classes are public or not.

If I were designing an application which communicated on a network as well as talked to a database, I would split the two pieces into separate segments, or in Java, packages. Inside each package, I would likely have a Connection class, which has completely different meanings within the network and database packages. Inside those packages, especially if the Connection class was internal to the package only, I could name both classes Connection without any concern and the code inside the package would immediately understand what Connection actually meant. This is possible in Java because the actual class names are com.cod3r.app.network.Connection and com.cod3r.app.database.Connection. Since Objective-C does not have namespaces, I would have to name these NetworkConnection and DatabaseConnection.

Now, take the above scenario, and add another type of network connection. Then take that new network connection and add new specific case to it, making a new class. In Java, the package name gets longer where as in Objective-C the class name gets longer. I have run into cases where this borders on ridiculous if one wants the class name to define what it actually does without ambiguity. The class is within the Sapphire plugin. In the project, all classes had the prefix Sapphire since it was a bundle included in another application and had to make sure there was never a class conflict. The project has the concept of a Directory and a VirtualDirectory was a directory which wasn’t associated with a directory in the file system. There is a type of VirtualDirectory that was Custom meaning it was defined by the user instead of already in the code. Finally, this particular class is responsible for importing these CustomVirtualDirectory objects, making the final class titled SapphireCustomVirtualDirectoryImporter. In Java, this class would have been Importer within the net.nanopi.sapphire.directory.virtual.custom package. The difference is the fully qualified classname would only be used in the import statement, and the short class name would be used in the code, instead of the really long classname used in every location as seen in Objective-C. This becomes particularly relevant when it comes to code completion that produces a terribly long list until nearly the entire class name is typed.

The lack of namespace becomes problematic when one uses third party libraries. Take the above Sapphire example and another plugin developer finds a completely unrelated library titled Sapphire. If that library happened to have a directory titled SapphireDirectory, then both plugins cannot be loaded at the same time. Java goes even further with a two-level namespace such that two jars (bundles) with the same fully-qualified classname still don’t interfere since they are in separate jars.

Adding namespace is necessary for adding inner-classes, which Objective-C outright doesn’t use, but could in proper circumstances. Inner classes are useful for implementing delegate methods. When setting a delegate, one typically passed in the instance of an inner class rather than the current instance. Not adopting this model has the issue when a single class is set to be the delegate to multiple objects, such as being the delegate to two table views. Apple works around this design by making each delegate method have the first parameter be that of the object calling it’s delegate, such as the table view. This means if the code is different between the two, every single delegate method needs have an if statement to determine which table view is being processed, and eliminates the ability of one to skip implementing an optional method for one table but not the other. Both of these problems are eliminated with inner-classes. Finally, the lack of inner-classes severely cripples the ability of a super-class to use the Key Value Observing within Objective-C since the delegate and unregister methods were written in a way that really require an inner-class to work properly (I can see how to easily break some code in a sub-class or super-class since this was designed so badly).

Impact on Runtime:
Small. I don’t know the specifics of the runtime, so I can’t judge the exact impact, but this will result in longer effective class names, which may increase lookup times. Inner-classes would need an instance variable for their outer-class to access it’s instance variables, resulting in additional pointer deference for accessing outer-class variables.

Impact on Code:
No longer need to create necessarily long class names; programmer can use short class name without concern. Frameworks need not have a class prefix. More flexibility in object design.

This is the third is a series of blog posts I’m writing on things that Objective-C can learn from Java. The other parts can be found here:
Part 1 (Generics)
Part 2 (Abstract Classes)
Part 3 (Single Source File)
Part 4 (Namespace)

Objective-C still retains a lot of its heritage from it’s C beginnings. This includes using two files, a header and a source file, for each class. In a strictly object oriented environment, the header file contains the class definition (super-class and instance variables), public property definitions, and any public function declarations. The source file contains all of the function implementations, including synthesize statements. In contrast, Java contains all the functions of both files in a single file. To one who knows better, as in one who has used the single file environment, the two files for each class becomes a pain.

As to why this is a pain, one needs only to visit the following scenario: Add a property called name to the Person object. In Objective-C, one needs to add the instance variable to the class definition and the property declaration to the header file. Then, add a @synthesize statement to the implementation and add [name release]; in the dealloc (I’m neglecting Objective-C’s ability to create the instance variable in modern runtimes since it denies direct access to it in the code). In contrast, Java needs the instance variable added to the class, and in the same file add the setters and getters (which if using Eclipse, can be auto-generated). Java is able to accomplish this because it uses a two-pass compiler. One pass parses the class definition and function declarations, and the second generates the actual code. Any import statements only need the first pass of each file.

In Objective-C, some of this pain can be eliminated using my fork of ObjectiveCAnnotate, but this is only part of the way to what should be done. What Objective-C really needs is to use a single source file, and auto-generate the equivalent header file when the source file is saved (and save it only if it is different to reduce unnecessary re-compiles). This serves as the equivalent of Java’s first complier pass. Then, the actually compile step executes the second pass, using the generated header and the code within the source file. Using the paradigm, several changes should be made to the source file. The obvious is adding a public (or maybe @public) to functions that should be included in the header file. Additionally, the property syntax can be combined with the instance variable declaration and possibly with synthesize to create something like @property (nonatomic, retain, synthesize) NSString *name to take the place of the instance variable declaration, the property declaration, and the synthesize statement. Since this is by far the most common use case, why not simplify it to make things easier for the developer? The instance variable still needs to be in dealloc, but now changes in instance variables has been reduced to two places.

This change doesn’t completely eliminate the need for header files. The old C-style declarations, such as C-functions, structs, enums, externs, typedefs, and defines, would still need to be in a header file on their own. Since most classes do not make these declarations, most classes wouldn’t need a distinct header file. In the cases where such a definition is made, it is often better style to include all of the definitions in a single types header file for the framework/project.

This does necessitate a change to the import statements for a class. In the two file environment, one can separate the import statements between the header and source files, but in a single file, this separation no longer exists. However, the compiler could be made smart enough to track the locations of types it inserts in the generated header file, and include those location in the header file’s import statements. This would mean the header file would contain the import statements for the super-class, and any C-style declarations only. There is no need at all to include the import statements for other classes, as the existing @class declaration tells the compiler all it needs to know at this stage. This would also eliminate the bad coding practice of including unnecessary import statements in the header file, a practice which I’ve seen too often by new programmers who were never taught of its dangers.

Impact on Runtime:
None, this is pre-processor only

Impact on Code:
Reduction in code complexity, ease in modification. Reduction in need to reference two files to understand a single class.

Older Posts »