pycares 4 released, mistakes were fixed

pycares is a Python module which provides an interface to c-ares. c-ares is a C library that performs DNS requests and name resolutions asynchronously.

Finally, after a long time, I managed to make a new pycares release. Introducing pycares 4.0.0. This is an important one (note the major number change!) here are the most important features from this release:

  • Dropped support for Python <= 3.5, the supported Python versions are 3.6-3.9
  • Added getaddrinfo()
  • Added support for CAA queries
  • Updated c-ares to the latest version
  • Dropped custom patches from the embedded c-ares library
  • Added ability to use the system provided c-ares library
  • Refactor automation of the release process and wheel generation and upload to PyPI

I’m looking for help maintaining this module further, if you are interested, please comment here.

While working on this release I had some thoughts and reflections, if you are interested in those come with me in a trip down memory lane.

Read more

pycares 3.1.0 released!

Finally back blogging… it’s been a while. Today I bring you a new pycares release: 3.1.0

pycares is a Python module which provides an interface to c-ares. c-ares is a C library that performs DNS requests and name resolutions asynchronously.

This release was relatively small, but I’m really happy about the automation work that I managed to do before the release, which should help with making the next releases faster and better.

Thanks to the automation work this release includes binary wheels for Python 3.5-3.8 on Windows, macOS and GNU/Linux.

How is this done? Well, pycares is now using 3 different CIs:

  • Travis: runs tests on GNU/Linux and it builds release wheels for all 3 platforms (this las key bit is new!)
  • GitHub Actions: runs tests on macOS
  • AppVeyor: runs tests on Windows

Thanks to these 3 free services, I couldn’t have done it without them! ❤️ Also huge thanks to Joe Rickerby for creating cibuildwheel it really made this a whole lot easier.

Skookum JS 18.6.0 released!

2 years have passed since the last Skookum JS release, so here we are, with a new release, and (maybe) a new plan.

But first, for those who don’t remember: what is Skookum JS (sjs)?

Skookum JS (or sjs for short) is a simple JavaScript runtime built on top of the Duktape JavaScript engine, with a simple POSIX-y API.

I guess the first question is “what’s with the version number?”. Fair point. I decided to switch to calendar versioning and give it a try, so since we are in June 2018, it’s time for a 18.6.0.

The focus of this release was to add more features and make it more CommonJS-alike, as I mentioned on my previous sjs post, but as time passed I realized I was wrong.

When I designed sjs I got heavily inspired by the runtime I knew the most: Python. This means having a small binary and “native addons” as shared libraries, in addition to a sizeable standard library. That’s all great, but it brings significant trouble because all those need to be in some path which the runtime will query, take (potentially) long time to load, and having multiple versions installed side by side is not easy. By contrast, Node takes the single binary approach: all the native modules needed for the standard library are part of the single binary, and so is the standard library itself. So I decided to do the same.

With this release, sjs is a single binary with all previous native modules embedded, as well as the standard library. I’d like to point out how I went about embedding the standard library, because that was a fun discovery: incbin. Incbin uses assembly to embed binaries into an executable, so that’s how I chose to embed all the JavaScript in the standard library onto the binary? Ugly? Maybe. Does it work? You bet!

sjs remains a toy project I like to hack on every now and then, and it’s now clear to me that my original design was flawed in many levels, so with this release I’m fixing one of those mistakes. Hopefully there will be more to come!

You can check the release notes here, check the code on GitHub, and check the documentation here.

Streaming a webcam to a Jitsi Meet room

Every so often I see the following question:

How can I stream a webcam to a Jitsi Meet room?

Wait, isn’t this just like “joining” a room? Not quite. One may want to have some dedicated contraption streaming a webcam to a room. Think of a homemade security camera system or something alike.

This probably gets asked for other WebRTC conferencing services too. The way I see it, there are 2 ways to go about it:

  • Buid a way (on the server) to accept a stream sent with ffmpeg or gstreamer, and broadcast that.
  • Use a browser.

I know what you’re thinking: “Saúl, running an entire browser is overkill!”. Maybe. It will consume more RAM, yeah, but I argue the dominating factor here is video capture and encoding, not JavaScript execution, the DOM and other shenanigans.

Also, when all you have is a hammer, everything looks like a nail.

With the advent of headless mode in both Chrome and Firefox, this option looks more enticing than ever, so let’s roll our sleves and give it a shot.

I’m going to use Google’s puppeteer library, which runs Chrome headless to join a Jitsi Meet room. Being a headless client, we can cut down some of Jitsi Meet’s features in order to reduce the required resources:

  • No need to receive video
  • Disable simulcast (only encode video once)
  • No audio levels

I could probably add some more, but those should be enough to make a difference. The astute amongst you may think “but Saúl, disabling simulcast means every streamer will send an HD stream, I can’t cope with so many!”. Great point! Here we are going to rely on adaptivity, so no need to worry, if the client can only receive a single HD stream, the rest will be suspended, but you can switch between them just fine!

Here is the code (I also got to play with async / await for the first time, which is pretty cool):

const puppeteer = require('puppeteer');
// Streams the first webcam in the system to the specified Jitsi Meet room. Audio is currently
// not sent, but it can be easily enabled by disabling the corresponding setting in `meetArgs`.
// – Detect if we are kicked from the room
// – Support authenticated deployments
// NOTE: only tested on GNU/Linux.
async function main(room, baseUrl='') {
const chromeArgs = [
// Disable sandboxing, gives an error on Linux
// Automatically give permission to use media devices
// Silence all output, just in case
const meetArgs = [
// Disable receiving of video
// Mute our audio
// Don't use simulcast to save resources on the sender (our) side
// No need to process audio levels
// Disable P2P mode due to a bug in Jitsi Meet
const url = `${baseUrl}/${room}#${meetArgs.join('&')}`;
console.log(`Loading ${url}`);
const browser = await puppeteer.launch({ args: chromeArgs, handleSIGINT: false });
const page = await browser.newPage();
// Manual handling on SIGINT to gracefully hangup and exit
process.on('SIGINT', async () => {
await page.evaluate('APP.conference.hangup();');
await page.close();
await page.goto(url);
// Set some friendly display name
await page.evaluate('APP.conference._room.setDisplayName("Streamer");');
main(process.argv[2] || 'test123');

view raw


hosted with ❤ by GitHub

My original intent here was to use some inexpensive (and not very powerful) device such as the Raspberry Pi, but alas puppeteer doesn’t yet support ARM devices 🙁

Happy streaming!

Upcycling an old Mac Mini with ChromiumOS

I’ve had an (now) old Mac Mini 2,1 for about 10 years now and it has served me well. It used to be my desktop machine, then media center, then small home server.

My trusty old friend

At some point I realized I had moved all services except the printing service, so I thought it was about time I decommissioned it, but it deserved one last shot, so here we are 🙂

Read more

pyuv 1.4.0 released

Today I finally found some time to put together a new pyuv release! Oh, but what is pyuv? I’m glad you asked!

pyuv is a Python module which provides an interface to libuv. libuv is a high performance asynchronous networking and platform abstraction library.

This a big one. Here are some of the highlights:

  • PyPy support (finally!)
  • CPython 3.6 support
  • Overhauled build system (we no longer rely on the libuv build system)
  • Linux and Windows wheels published on PyPI
  • New co-maintainer! Say hi to Marc Schlaich!

See the full changelog here.

I just realized the last release was over a year ago. Time flies! At any rate, here it is now. Enjoy!

How to get AppRTCMobile for Android

More often than not, when reporting issues in the WebRTC bug tracker, you’ll be asked to reproduce it with AppRTCMobile (the “reference” or “demo” app of sorts). This may be a hassle because you might not be able to build it yourself.

Worry not! Google archives all the apk builds from their CI system and you can download it from there. I’m not sure if this publicly available information, but I couldn’t find it anywhere, so here we go!

  • Go to this site and pick the Android builder you desire
  • Then click on the latest successful build (this one for example)
  • Next, locate the “gsutil upload” step (it’s 22 at the time of this writing)
  • There should be a “gsutil.upload” link below it (this one for example)
  • Click it to download the file!

The downloaded file is a zip file containing the apk. Installing it is simple, connect your Android device and do:

adb install AppRTCMobile.apk


Winds of change

I’ve tried to mentally write this blog post for weeks, but there are just too many things to say, so I’m just going to get on with it and see what happens.

It’s with a weird feeling in my stomach that I say goodbye to AG Projects.  Starting in January I’ll be an Atlassian employee, joining Emil Ivov and the Jitsi team taking on new challenges.

This was by far the toughest decision I’ve ever made in my carrier. Tougher than leaving my home town 7 years ago when I came to Amsterdam.

“Relax, it’s only work” or so the saying goes. For me work is never just work. For better or worse I pour part of my soul into everything I do, otherwise I wouldn’t be able to do it. This means making choices is harder because feelings arise. Moreover, in this case it’s definitely not just work. Moving to Amsterdam changed my life. I’ve met people I wouldn’t have met otherwise, and most importantly, my wife found the motivating job she longed.

These past 7 years have been amazing. I’ve been able to travel the world and attend conferences, write an RFC, meet some amazing people and write the code I wanted, the way I wanted. 7 years is equivalent to eternity at Internet scale, but Adrian always found something awesome for us to work on next.

I consider myself very fortunate to have found great friends, coworkers and mentors throughout my journey in life. They all taught me things I didn’t know and I like to think we learned some others together.  That’s why it’s so damn hard to say goodbye.

From the bottom of my heart, thank you. Best wishes for the future and keep on rocking!

As for my future at Atlassian, I’m really excited for what’s to come! I’m joining a team of extremely talented individuals which have a track record of creating top notch software and I’m glad to be a part of that.

The best things in life are often waiting for you at the exit ramp of your comfort zone.

Here is to the future! We’ll always have Amsterdam.

PS: Hey, they have an opening right now, so if you want to work with these great people and have a chance to criticize my code and design choices you should definitely apply!

Liverpool Summer Camp 2016

These are my last few days here in Liverpool, and as I sit in a half-empty house, looking at the Mersey through the window, all I can think of is what a ride it’s been.

We came here earlier this year because my wife was working on a project and I tagged along.  Since she had to work long hours we looked for a coworking place where I could work from, to force me out of the house and interact with the autochthonous species.

The place we found forever changed me, in ways I’d never foresee. Allow me to introduce you to DoES Liverpool. For many, Liverpool is home of The Beatles and a place where you’ll never walk alone. Not for me. For me Liverpool will always be home of DoES, where I developed my dormant maker skills and brought them to a whole new level.

Browsing through the website I discovered there were laser cutters and 3D printers available, that got me hooked on the spot. Bu then I came across the about page, which outlines their mission, so I fell in love.


The people there are incredible. Everyone is ready to teach you how things work, have a chat about what they are working on, and help you out when something doesn’t work as expected. At first I wasn’t sure if it’s the maker spirit that makes everyone nice around here or something about the wind on the Merseyside, but be that as it may, Scousers are a great bunch.

Being happy and having a sense of accomplishment are key to producing good work, and thanks to the positive and makery environment, these past few months have been really productive for me. I’m really going to miss this.

If you find yourself in Liverpool, visit DoES, your first day will be free if you bring cake, what’s there not to like?

I guess this is goodbye. Thanks for all the tips and tricks, for maker nights and maker days, and for bearing with me and my million questions 🙂 I hope you folks find the right building to grow DoES and make it even greater. Hopefully I can visit one day.

So long Liverpool, I’ll cherish the memories; and godspeed, DoES, godspeed!