In case you missed the news, it’s already May! The year is moving quick and so are we.
A little over two weeks ago we released Oddworks 2.0. Under the hood, we moved from using Seneca.js to our own event broadcast and queue API for Node.js called oddcast. This was a calculated change and along with it we began to make the entirety of Oddworks a lot more extensible and modular.
To go along with the move to 2.0, we’ve done a little spring cleaning and reorganized a few of our repos to make the intentions of Oddworks clearer.
So here we go!
@oddnetworks/oddworks
A key change here is that we’ve packaged up oddworks and released it on NPM.
The goal with Oddworks has and continues to be to allow developers to quickly spin up a platform for serving OTT content in a way that fits their particular business needs. As such, providing an out-of-the-box configuration seemed silly and so we’ve removed that part. More on that below.
Now, including Oddworks into your Node.js project is as easy as:
npm install --save @oddnetworks/oddworks
To read more on how Oddworks, well.. works, head over to our ever-improving Github repo https://github.com/oddnetworks/oddworks
@oddnetworks/oddworks-cli
The oddworks-cli tool now lives in it’s own NPM package, too.
Installing is as easy as:
npm install --global @oddnetworks/oddworks-cli
The Oddworks CLI tool can be used to generate API access tokens and a few other helpful things.
We have some big plans for this handy little tool, so stay tuned.
Oddworks Example Server
Our first of many, the example-single-process Oddworks Server now lives on its own and can be deployed with a single click of the mouse.
This is a super handy reference application that will help developers understand how the pieces of Oddworks can be composed into a server that fits the needs of individual channels.
Another great benefit is that now developers can have their own Odd Playground to pair with our SDKs, and can begin making their apps right away.
Improved Documentation
One of our biggest goals is to provide clear and concise documentation on how Oddworks is composed and how it can be used to suit your OTT needs.
This is a continuing effort and we’ve been devoting equal time to both code and docs. We hope you find it useful and if there is ever a question or contribution, please do not hesitate to ping us in slack or open a pull request!
Until next time…
Phew! That was a bunch of updates, but we’re just getting started. Stay tuned to Odd Networks for more awesome OTT developments.
When we decided to rewrite Oddworks we wanted to keep some of the original patterns from the original. Most notablely the pattern matching for defining logic and connecting that logic with a common message bus. This also allowed us to embrace the service oriented architecture (SOA).
Oddcast
Oddworks services communicate with each other with Oddcast message bus channels. Those channels can be set up on top of any type of communication method like TCP, pub/sub, queues, etc called "transports". The most basic form of a transport is an in-process transport in which all messages are sent around within a single Node process. Our Example Single Process Server illustrates this very well.
If, for some reason, you needed to disrtibute Oddworks across multiple servers you lose the ability to use the in-process transport. This is where you would need to chose another type. The Oddcast TCP Transport is the next step up you could leverage. With this you could deploy the Oddworks Catalog API server on one machine and the Oddworks Identity API server on another machine and have them communicate over TCP, but put them both behind the same domain. This would allow you to scale up/down each service individually based on your needs. For instance, maybe your Identity Service gets heavy traffic you could add a caching layer in front of just that service and leave the others alone.
This is merely the beginning of the flexibility Oddworks offers by using Oddcast to communicate. You can start by deploying a small single server instance and scale up accordingly by breaking out the serverices into their own separate processes and eventually their own servers and coninually to scale horizontally.
If you have any questions please join us in Slack!
While we provide compiled binaries of our iOS and tvOS frameworks for you to use when developing client applicaitons for Apple devices, using these compiled frameworks has limitations.
The main issue is you can not debug into the SDK code to see what’s happening. Its not easy to make a quick change to SDK code to see the effects, and its just generally tedious to recompile the SDK each time you need to make a small change.
Apple’s Xcode has a nice solution to our problem in Workspaces. A workspace is an Xcode environment that allows you to have multiple projects open at one time. Code from one project can be used in the others and dependencies can be shared. You can also debug into another project if that project’s code is used in another of the Workspaces Projects.
Lets get this setup
Since a Workspace is just a collection of Xcode Projects, we will begin by selecting File > New Workspace from the Xcode menu. You can place the Workspace file anywhere you like. It does not need to be saved with your Project files.
Next you need to add the Projects to the Workspace. Lets start by adding the OddSDK project. If you have not already cloned the SDK to your computer you will want to do so. In Xcode from the Project Navigator (the leftmost panel that lists your projects files) select the + button in the lower left or right click to show the add files dialog. You can create and add a new file or project but what we want to do is add the existing OddSDK project you have cloned to your computer.
Adding the Project files to the Workspace
Select ‘Add files to ’ and navigate to the project folder on your drive. Select the Xcode Project file for the SDK (OddSDK.xcodeproj) and press the ‘Add’ button in the lower right.
You should see the OddSDK project appear in the Project Navigator.
The newly added OddSDK Project
protip: if you don’t see all the files of the project you most likely already have that project open in Xcode. You will need to remove the reference to the project from the Project Navigator, close the other instance of the OddSDK project and start over.
Once you have the OddSDK in your project you can add the client app project you want to take advatange of the SDK. You can either repeat the same steps to add an existing Xcode project or select ‘New Project’ from the Workspaces add files dialog.
For the rest of this post we will assume you added the iOS Sample app from our Sample App Repo.
The two Projects in the Workspace
The OddSampleApp, and your other client apps, will need to link against the OddSDK (or OddSDKtvOS) in order to work with Oddworks. The process of linking them to work in the Workspace is very similar to linking against the static binary frameworks. From the OddSampleApp target select the + button in the lower left of the ‘Linked Frameworks and Libraries’ section to add the framework product of the OddSDK project that shares your Workspace.
Selecting the Framework
One further setting may be required to make sure everything is hooked up correctly. Since the SDK is written in Swift, you may need to tell Xcode about the use of Swift code in your embedded SDK. Under the ‘Build Settings’ tab for your client apps target search for ‘Emebedded’ and check that ‘Embedded Content Contains Swift Code’ is set to Yes.
Configuring for Embedded Swift Content
Once this is all set you should be able to run your client app in the simulator. You can now set breakpoints in the SDK project and they will be caught when your client app executes. You can quickly make changes to the SDK code and immediately run your project and see the effect.
Building and running on a device may require additional setup that we won’t cover here.
I hope this post is helpful in getting you setup to work with the Oddworks SDK in a simpler more effective way. Thanks for trying our stuff. Let us know what you build.
Nearly 3 weeks ago we open sourced our over-the-top video distribution platform (Oddworks), written almost entirely in JavaScript for Node.js. Totally unrelated we simultaneously began experiencing issues with load on our main hosted service using that very same open source platform to deliver content to paying viewers. This was due to a new, and very popular TV show that launched on our hosted product. The catch was that this show was pre-recorded and made available to subscribed viewers at 9pm each night.
This scheduled release of new content to eager subscribers who were required to authenticate their devices to consume the content created a perfect storm to maximize the amount of load our systems could possibly experience. It resulted in us staying up each night to manually spin up more instances of the app and re-configure the edge cache to try to limit the damage. We eventually diagnosed the problem, and refactored the way our components and services communicated wich resulted in massive performance gains. The system is now handling the thundering herd without blinking.
We Need Your Help
Since the fix for our production issues meant ripping out the way our different components and services speak with one another, we now need to invent a new way for that to happen. This is actually great news, because you get to join us in debating the eventual solution! And we all know how software engineers openly and effectively debate solutions to thorny problems without trolling or flame wars, right?! ;-)
The Problem
Anytime you're building a platform, you want to design it using loosely coupled components and services, right? We're no different. That is the end goal. For the sake of simplicity, we're not going to split hairs here, and we're going to call all our components and services just "services" from now on.
Also, a reminder, this is currently a 100% Node.js platform.
Anyway, to get loosely coupled services we need a standardized way of doing 2 things:
A common way to communicate between services
A common way of injecting dependencies into services Here our our thoughts on these two items so far:
Service Communication
We've been experiencing a growing love affair with pattern matching APIs. Here's the way it works: Services expose functions which attach themselves to some kind of pattern. Messages are then distributed into the system and when messages match a pattern they are routed to the matching function. Perhaps the simplest and most common example is using URL paths to route HTTP requests to controllers.
Another example I like a lot is the way Erlang function match against parameters. So, in JavaScript we might see a function like this:
function greet(gender, name) { if (gender === 'male') { console.log('Hello, Mr. %s!', name); } else if (gender === 'female') { console.log('Hello, Mrs. %s!', name); } else { console.log('Hello, %s!', name); } }
But, in Erlang, you can loosely couple several different, use case specific versions of that function using pattern matching:
The Seneca.js framework implements pattern matching in JavaScript very well in our opinion:
seneca.add({role: 'math', cmd: 'sum'}, function (msg, respond) { var sum = msg.left + msg.right respond(null, {answer: sum}) })
However, there are a few problems with Seneca.js that were kind of nagging us, and then a final nail in the coffin during our 2 weeks of performance issues (which we'll outline in a future blog post). In short, we wrote our own message passing and pattern matching system called Oddcast which I'll outline below.
Dependency Injection
You can call it dependency injection, or inversion of control, or whatever. There are detailed explanations of dependency injection from Martin Fowler and Microsoft in a very enterprisy long method naming sort of way. But, my favorite explanation comes from James Shore:
Dependency injection means giving an object its instance variables. Really. That's it.
If you read that ^ article, there's really nothing more to say here about dependency injection. So, go read it.
Potential Solution(s)
Message Passing and Pattern Matching with Oddcast
We think message passing the pattern matching are still the way go for loosely coupled communication between modules. To that end, we wrote a message passing and pattern matching library for Node.js called Oddcast. It separates messages into 3 types of channels:
Event channel: Send and forget, multiple listeners.
Command channel: Send and forget, single handler.
Request channel: Send message, single handler, wait for response.
The use case for the Event and Request channels is kind of obvious, but the use case for the Command channel may not be so plain. The Command channel is for queueing up messages in a distributed queue or making state changes to a canonical datastore where the response is not important to the caller.
Dependency Injection: The 'App' Object.
As an application initializes, the core Oddworks system would spin off several lifecycle events which services could then listen to in order to attach themselves to the application. The listeners would each be passed the application instance, which would have configs, the Oddcast bus, Express App, and various other dependencies (like database connections) attached to it.
Example
Here is what a plugin for managing authentication information might look like:
module.exports = function identityService(init) { // The 'afterServices' event ensures that the app configuration is loaded and // database services have been initialized. init.on('afterServices', function (app) { var db = store.initialize(app); app.API.bus.queryHandler( {role: 'identity', cmd: 'fetchOrganization'}, db.fetchOrganization ); app.API.bus.queryHandler( {role: 'identity', cmd: 'upsertOrganization'}, db.upsertOrganization ); app.API.bus.queryHandler( {role: 'identity', cmd: 'fetchDevice'}, db.fetchDevice ); app.API.bus.queryHandler( {role: 'identity', cmd: 'upsertDevice'}, db.upsertDevice ); }); // The 'afterMiddleware' event ensures the core Express.js middleware is // already attached by Oddworks. init.on('afterMiddleware', function (app) { // Only attach middlware if it's configured to do so for this app. if (app.configs.myAuthPlugin.attachMiddleware) { app.API.express.use(middleware(app, {hash: 'headers.accessToken.deviceId'})); } }); // The 'afterHTTPRoutes' event ensures the core Express.js routes for the // Oddworks content server have already been set, which means this // route will override, which is what we want. init.on('afterHTTPRoutes', function (app) { // Only attach a router if it's configured to do so for this app. if (app.configs.myAuthPlugin.attachRouter) { app.API.express.use('/identity', router(app)); } }); };
The app Object passed into the initialization event handlers would have the following properties:
app.name - Name of the app from package.json
app.version - Version String of the app from package.json
app.appdir - The root directory file path of the app
app.environment - The current operating environment String
In this way, the entire Oddworks platform is easily extendable by writing a service, defining patterns to match, and potentially attaching HTTP routes. Writing a plugin to customize your system should be fairly straightforward.
What do you think? Is this crazy? What are we missing?
You can find this article on Hacker News or GitHub. Upvote. Comment. Commit.
Find us on Twitter or Slack, and don’t forget to check out our web-site. Feel free to submit your thoughts to our publication too, Odd Networks.
Here at Odd Networks we have completely embraced Swift for our Apple platform development. Our iOS and tvOS SDKs are written in Swift. All our client applications to date have been written in Swift.
If you follow the twitters and blogosphere, you may have come across many long time developers hesitating to move to Swift. While there are certainly reasons Swift may not be the right choice for every project, the levels of fear and negativity I see around moving to Swift is disheartening.
Sure, if you have large legacy Objective-C code bases, then porting to Swift is probably a non-starter. I’m sure there are many legitimate reasons not to do a project with Swift.
I’m more concerned with the developers, who point out that Swift is not mature and each new release requires auditing, and updating your code to continue to work. Another complaint is the dev tools are not up to par. Both of these things are true, but how serious an issue are they?
We just ported a handful of apps and our SDKs to the most recent update of Swift, version 2.2. It took one afternoon. Our code is better for it.
Was it worth it? Absolutely.
One new feature for Swift 2.2 is the removal of selectors as String objects. Yes, this results in more verbose selector declarations, but it also has the side effect of improved code safety. Now the compiler can verify a selector actually exists, potentially avoiding a crash down the road.
In our porting to Swift 2.2 we discovered 2 potential crashing bugs based on this very issue. We fixed them in minutes and our code is safer for having ported.
Are the dev tools, Xcode specifically, lagging behind the Objective-C functionality? Yes, a bit but nothing that stops you from getting real work done.
Sure you can’t refactor Swift code yet, but I have faith you will sooner rather than later.
Is the compiler a bit slower when working in Swift? I guess so but it still takes just seconds.
Have you tried to experiment with your Swift code in a playground? Objective-C doesn’t have that feature and its a great way to try things out.
Our Swift projects probably have almost half the lines of code of a similar Objective-C. We get more done, faster.
So we write less code. Do more and do it safer then similar Objective-C code.
Apple has decided that Swift is the future and and so have we. If you’re starting a new project, perhaps an OTT app?, might we suggest giving Swift a try and embracing the future? Don’t believe the naysayers. Swift is good stuff.
p.s.
Like most Apple developers we have a long history with Objective-C and we love it. This post is not meant to knock Objective-C. We just see people generating FUD around Swift and would like to offer an alternate opinion.
Finally, if for whatever reason, you have to continue to work in Objective-C when using our Odd platform we fully support that too. Pick your tool and make something great.
If you have any thoughts or ideas you want to share with us and with everyone else interested in over-the-top broadcasting and development of new kind of video applications, find us on Twitter or Slack, and don’t forget to check out our web-site. Feel free to submit your thoughts to our publication too, Odd Networks.
I read a google article the other day about a self-documented Makefile. The TL;DR is you can add comments to each of the commands in the Makefile. Then by just running make from the command line it will print both the command and the associated comment to explain the entire Makefile at a quick glance. Not only is this very helpful, but it also rids your README of this shit you constantly having to keep updated:
Running
$ npm install $ npm run dev
Testing and Linting
$ npm run linter $ npm test
Then when you add another script to package.json you have to update your README to document it…if you remember to. Instead you can take a lesson from the Makefile article above and add some inline comments to your npm scripts.
package.json
“scripts”: { “dev”: “### Start the server in dev mode and watch for file changes\n nodemon index.js -e js,json”, “test”: “### Run the linter and test suite\n npm run lint && npm run tape “, “tape”: “### Run just the test suite\n tape ‘test/**/*_test.js’ | tap-spec”, “lint”: “### Run just the linter\n xo”, “start”: “### Start the server in production mode\n node index.js -e js,json”, “sec”: “### Security check the packages\n ./node_modules/.bin/nsp check -o json — warn-only” },
This is what you get now when you just run npm run.
$ npm run Lifecycle scripts included in npm-test-project: test ### Run the linter and test suite npm run lint && npm run tape start ### Start the server in production mode node index.js available via `npm run-script`: dev ### Start the server in dev mode and watch for file changes nodemon index.js tape ### Run just the test suite tape ‘test/**/*_test.js’ | tap-spec lint ### Run just the linter xo sec ### Security check the packages ./node_modules/.bin/nsp check -o json — warn-only
By wrapping the documentation text between a # and \n (newline) character it will display the text and still allow the actual command to run. You can go a little crazier and add \t (tab) characters and even emojis to make it really awesome.
$ npm run Lifecycle scripts included in npm-test-project: test # 🚦 Run the linter and test suite npm run lint && npm run tape start # 🚀 Start the server in production mode node index.js -e js,json available via `npm run-script`: dev # 🖥 Start the server in dev mode and watch for file changes nodemon index.js -e js,json tape # ⭕️ Run just the test suite tape ‘test/**/*_test.js’ | tap-spec lint # ⭕️ Run just the linter xo sec # 🔒 Security check the packages ./node_modules/.bin/nsp check -o json — warn-only
Now you can clean up your README file and add all the proper documentation to the package.json file where it belongs. If you have any other tricks about this send me a PR for this article and I will update it!
We are on Product Hunt
You can also find us here: Twitter / Website / GitHub / Slack
Here is how to find Blain: Twitter / Website / GitHub
Key points from a webinar hosted by Paula Minardi and Jim O’Neill from Ooyala. Topic: “2016 State of the Broadcast Industry”.
OTT technology has undeniably entered the mainstream, which is why it is important to pay attention to changes and trends if you are in any way connected to the broadcasting industry. Those who stay informed know more about what is relevant and how to win over viewers, and most importantly where to find them.
During the webinar, we’ve learned that OTT trends are primarily driven by millennials. Millennials are an important group to be pursued for their attention and willingness to invest their time and money into enjoying content. One of the most important features content must have is to be available at any time on any device. Currently, it is highly desired by anyone to be able to “take their content with them”. It is all about entertainment and video on-the-go, as mobile-first options are becoming more popular.
We are a generation that is lucky to have access to our favourite TV shows, movies, and networks as long as we have access to internet. Traditional broadcasting landscape is changing, and so are our TV viewing habits. Some of us are parents that are opting out for cord-cutting options, which means the children will be growing up as cord-nevers and will not know the difference between cable networks and app driven programming.
Another thing to keep in mind is that location matters for all parties involved in the OTT industry. If you are a content producer, know which regions your content can be delivered to. Think about expanding to many regions to attract more viewers, to grow your audience, and to win over their hearts and minds with your unique content.
A great example of aiming for as many regions as possible is Netflix, and their recent expansion to over 130 countries around the world.
With improvement in quality and sizes of screens on mobile devices, not only the viewer experience becomes better, but networks and content creators gain more traction with larger inventory of devices.
According to Ooyala’s presentation, about 30% of people in North America enjoy full-length TV, and 20% full-length movies on their mobile screens. These numbers are making it clear that viewing habits are changing.
However, with changes in viewing habits and broadcasting come changes in the advertising industry. It is heavily influenced by the switch from traditional cable-driven TV to subscription and web-based video options. Hence, a closer attention will be paid to tracking such metrics as viewer behavior and actions. Despite significant revenue losses in advertising revenue, the advertising industry keeps innovating and solving such problems in various creative ways, relying increasingly on data-driven models.
OTT has influenced broadcasting positively because it allows viewers to no longer feel restricted by scheduling, locations, and devices. Producers are encouraged to explore innovation and to experiment with social features and on-the-go options. Internet connectivity in a video making business opens doors to creative and original content — for example new and authentic productions with branded content, specific to networks or events. Video libraries also keep growing based on opportunities and customer demand.
Numbers presented by Ooyala showed that around 10% of Americans stream videos on TV-connected devices daily. And this trend is going to keep growing; hence, the prediction of total video sharing traffic to be 70% by the year 2021.
A growing popularity of linear and live video is also connected to the population’s mobility on a global scale. People move and change connection providers, which drives demand for more broadband access across the world. Therefore, OTT driven technology and information about networks travels freely around the world attracting more attention and interest. In turn, the growing audience requires changes in broadband regulations for wider and more open access to informational and entertainment content.
All this said, there is a lot of good things to come in the future of OTT. Programming trends and discoverability of original content, big demand for specific content (such as sport and political events), as well as the need to fill niche OTT spots (for example, children specific content) will remain in the spotlight. One of the most important issues to remain in focus will be figuring out the best monetization models for both content and ad producers. The webinar touched on some points about ad blocking global costs that averaged to $41 billion by 2016. However, there is hope that with more data-driven approach, appropriate ad targeting, and personalization of ad content, favorability of commercial content is estimated to be at 40%. We also want to highlight, that networks should have strong strategies in place regarding branding content accordingly and successfully, focusing on audience’s needs, consumer education, and finding the right market, along with not being afraid to start small.
All we can say is good luck to all of the producers out there! Go out into the Odd world of video, and make your audiences happy! As for us, we will keep working on our cutting edge platform to help developers around the world build custom, state of the art video applications!
Find us on Twitter / Join us on Slack / Stop by our Website
Want to learn more about the state of affairs in over-the-top world? Follow our weekly updates, where we put together links to articles we come across during the week. Join us on our journey through the world of over-the-top technologies and more. We will share our discoveries, and we welcome you to contribute things you find/write/invent to make this world a better place, and to change the way we consume entertainment content.
Let’s get to it, and figure out what has the world of streaming media been up to.
No cable? No problem, you can still stream the Oscars tonight: https://t.co/GlkfUZvycd
Analyst tells cable: Mobile a real threat to operators future broadband revenues https://t.co/zSYUKl4rbN via @videomind
FCC digs into how restrictive cable contracts are preventing #streaming #TV https://t.co/shdxLnhtPa / @TechHive @OneJaredNewman #OTT
The battle for control of your TV has only just begun https://t.co/G2WrPYeYtD pic.twitter.com/4mJ6bPE5UD
On @backchnnl @scrawford explains Google's latest high speed Internet gambit and why it may be a game changer https://t.co/jwmivulmNw
What have we been up to, you ask?
We presented at Startup Tech Valley on Wednesday, 3.2.2016, and shared what we have been working on in the last year with hundreds of people, who joined us at the Browns Brewing in Troy, NY.
Thanks #StartupTechValley for having us https://t.co/jPSUJ2kisA It was one awesome evening @timesunion @BrownsBrewingCo @getwindrush
There are some developer updates for you too, if you are working on things like Linear Stream Stitching or figuring out how to Replicate tvOS Parallax Effect on Custom UIViews.
Stay tuned, and we’ll catch up with you next Friday for more Odd things.
Find us on Twitter or Medium, or check out our web-site.
Replicating tvOS Parallax Focus Effect on Custom UIViews
by Patrick McConnell
Nobody likes blockers; you’re coding away, and suddenly :boom: you hit a wall because there is a key piece of information missing. Many times, going into your mind palace or Google-ing your questions doesn’t yield any results — but have no fear. Inside the Odd Networks Developer blog, you can find helpful tips, hacks, and creative solutions to problems that might find their way into your projects. We want to make sure that you can focus your attention entirely on building new, state-of-the-art, cross-platform media applications.
Patrick, our iOS and tvOS developer, has shared information he collected while working on replicating tvOS parallax focus effect on custom UIviews. Without further ado, let’s move on to these generous and helpful instructions (accompanied by code examples).
There is a full sample project here if you want to follow along while reading.
iOS 7 introduced the concept of parallax views. When the user tilts their device the icons on the home screen will appear to shift position simulating a 3d effect.
With the Focus Engine, tvOS takes this to the next level where individual views respond to a user’s touch on the Siri Remote. This is a new interface paradigm and it takes some getting used to for users as well as developers.
By now you have seen examples of Apple TV applications and how the interface elements tilt, zoom and pan when you highlight them. Apple created a whole new way to interact with the user interface and they built the Focus Engine to do so.
But with any new technology there are growing pains. You will quickly discover if you drop some UIButtons or UIViews onto your Storyboard that many times they don’t behave like the new shiny focusable elements you want.
For a recent customers Apple TV app I was faced with a simple button with an icon and a text label. When the button was selected or in our brave new world, ‘focused’ it did nothing. This is not my first Apple TV app and I already understand things like responding to focus and coordinating the changes in focus with the Animation Coordinator. If you’re not familiar with these things a good place to start is Controlling the User Interface with the Apple TV Remote
What I wanted to get to the bottom of is how do you mimic the effect Apple uses when you focus on an image or other view.
I did what any self respecting developer would do and I googled it. I found some solutions based on older implementations around when iOS 7 first introduced the parallax home screen but nothing that show me how to mimic Apple’s effect.
Implementing the Parallax Effect
With iOS 7 Apple introduced UIMotionEffect as an abstract superclass that would help developers create new effects on views when the device was tilted. Working directly with UIMotionEffect subclasses while possible is tricky. You must conform to a few protocols and implement some methods to handle the interpolation between the devices orientation and the changes to your view. Thankfully they also provided UIInterpolatingMotionEffect to make the whole process much simpler.
UIInterpolatingMotionEffect allows you to basically decide what device orientation change you want to track and map that to some changes on your view. The Focus Engine then handles figuring out how much of the effect should be applied to your view based on ‘strength’ of the device orientation change.
Right now UIInterpolatingMotionEffect only implements two device orientation parameters to track, horizontal and vertical tilt. For tvOS these two are tied to the user’s finger location on the Siri remote.
So if we were to create a new motion effect and track the horizontal tilt our effect would be more pronounced the further the user’s finger is from where they started they swipe gesture on the remote. While UIMotionEffect also works on iOS devices we will limit the discussion here to the Apple TV.
The other piece of the puzzle is what do we change about the view when these touches occur?
Any property on a view that can be animated can be added to a motion effect. So properties like the views scale or center position can be connected to the user’s touch.
An example of a UIInterpolatingMotionEffect would look something like this:
What this says is when the user swipes on the remote horizontally we want to offset our views center along the X axis by up to 10 pixels.
The two required values minimumRelativeValue and maximumRelativeValue are the limits of this offset. So when the user swipes to the left as far as the remote will allow the view will shift 10 pixels and the same for the other direction. The xPan motion effect will handle deciding how much of that 10 pixel amount to offset the view depending on where the user’s finger is in their swipe gesture.
Actually Mimicking Apple’s Effect
I wanted to try to match Apple’s effect as best as possible and this is what I came up with:
The view should rotate about its center in relation to the swipe gesture
The view should move slightly along the axis related to the swipe gesture
The view should get a bit bigger when focused
The view should show a shadow below itself while focused
Not all of this can go into a motion effect some of these changes will be handled elsewhere in your code.
In order to tilt the view we the view we set the keypath string to the views layer.transform.rotation for each axis. This causes the view to appear to rotate about its center on either the X or Y access as appropriate. Note that the rotation is on the Y axis which means rotate about the Y axis not rotate vertically.
This will get your view tilting and panning while you swipe around on the Siri Remote but what about the zooming and shadows?
Since the zoom is not related to the user’s touch of the remote it doesn’t make sense to add it to the motion effect. Shadow is not a property that can be animated so it too can not be added to the motion effect.
The other thing we neglected to discuss to this point is we only want this effect applied to our view when it has focus. If you just add the motionEffect when the view is loaded it will always track the users’ movements on the remote and is definitely how Apple intended you to use the Focus Engine.
DidUpdateFocus… to the rescue
Apple has provided a method in the UIFocusEnvironment protocol that you can implement to be notified when your view becomes focused. This sounds like a good place to add our shiny new motion effects and other goodies.
If you subclass UIView or one of its subclasses you can add a method something like this:
I won’t go into too much detail about how this works but you can refer to Controlling the User Interface with the Apple TV Remote for more detailed information.
This method will be called when your view receives focus. To be sure we are a good subclass we call the super’s implementation of the method first
When the method is called you get two views as parameters. One is the view about to be focused, nextFocusedView and the other is the view that had focus previously, previouslyFocusedView. These two goodies are hiding in the UIFocusUpdateContext so we need to get at them with this line:
guard let nextFocusedView = context.nextFocusedView else { return }
This makes sure the nextFocusedView is not nil and skips all our machination if it is.
Then we get down to actually adding and removing effects depending on whether we are about to be focused or are about to lose focus
Here we check if we are gaining or losing focus and call the appropriate helper methods as well as our nice new class extension method addParallaxMotionEffect
In order for your animations to look correct Apple gives you an animation coordinator. It’s not clear what exactly this does but one can imagine it makes sure the unfocusing changes happen in time with the focusing changes. For now just wrap your changes within the addCoordinatedAnimations closure.
There is a corresponding helper method in the sample project linked at the bottom of this post that reverses these steps to remove the focus effect.
Once all this is hooked up, and it’s not all that much, you should have an effect approximating Apple’s parallax focus effect. It’s not a perfect match we don’t have the highlighting effect Apple uses for example.
Most of what I covered here is applicable to iOS with the exception of the focus updates. The motion effect code should work in an iOS project but you will need to trigger the effects in a different manner. If you make use of this with an iOS project I would love to hear about it.
I hope others find this helpful. I had a hard time finding all this information in one place so here is what I have learned thus far. I welcome suggestions, correction or any other input.
p.
And there you have it. We hope that Patrick’s findings were helpful in overcoming your blockers. Bookmark this page for future use, and follow us here or on Twitter for more updates about all things OTT.
Previously, we wrote a Medium post about HLS that explained who made it and how it was used to deliver high quality video over the internet. In this post we are going to dig deeper into the technology behind HLS itself, and show you how we are using it to provide you with a 24-hour linear stream of pre-recorded videos.
What do we mean by “linear stream”?
Think about your typical TV channel (if you still pay for cable). You pick a channel to watch, and you leave it there, and shows, movies, commercials seamlessly switch from one to the other without you having to do anything. On a typical on-demand TV channel or app, in our example, you have to manually browse a catalog of topics, categories, genres, etc. to find the next video to watch. This can be a very disruptive experience when all you want to do is veg out on the couch and watch TV.
With our linear stream stitching we provide our apps with a typical TV channel like experience called the “linear stream”. All you need to do is fire up your favorite Odd Networks powered app and watch the linear stream.
As a video publisher you can drag in multiple HLS video urls into the stream scheduler to fill out the 24-hour day or leave blank slots for our recommendation engine to fill in the gaps. After you are happy with your schedule of videos, you can then publish the newly stitched together linear stream, and put in with your apps or website! We don’t even have to re-encode anything.
How do we accomplish this voodoo magic we are speaking of?
Since HLS files are just plain text we can dynamically read links you provide for us, and we create a brand new one based on a schedule and algorithm. We even ensure the correct streams are provided to mobile and desktop viewers, depending on what stream qualities and bitrates their browsers and devices support.
Essentially we do the following behind the scenes:
Parse each main HLS url you provide as the scheduled content.
For each manifest file we parse the bitrate it specifies; so, we make sure we match the quality of the final stream.
Once we get all the video segments from each of the HLS urls, we dynamically stitch together a brand new HLS endless playlist with all the new segments from each of the original urls.
Once generated, you then have an endless looping linear stream of pre-recorded video that has been stitched together dynamically.
So if you are one of the many that has a lot of HLS video content in their possession, and you don’t have a live broadcast, we can help fill that need for a linear stream. If you don’t currently have videos available as HLS, not to worry, we can also help transcode your current video formats into HLS; so, you can take advantage of this solution.