SoundCloud for Developers

Discover, connect and build

Backstage Blog RSS

  • April 11th, 2014 Announcements Welcome to SoundCloud's redesigned developer site By Erik Michaels-Ober

    We've taken some time to bring all our developer resources together into a single site. In doing so, we've reorganized the layout to make things easier to find and also given the site a fresh new look.

    We hope you like it!

    If you have any feedback about the new design, follow @SoundCloudDev on Twitter and let us know.

  • April 11th, 2014 Announcements Security Security update: Heartbleed vulnerability in OpenSSL By Astera Schneeweisz

    HeartbleedOn Monday, April 7th, 2014, a major security vulnerability in OpenSSL was made public. The vulnerability was filed as CVE-2014-0160 and later dubbed “Heartbleed”, because the bug lies within OpenSSL’s heartbeat extension, which is used for keepalive monitoring. As a result of the bug, process memory can be read out remotely by an attacker—potentially including certificates, keys, credentials, tokens, or other sensitive data processed by the server.

    OpenSSL works as a cryptographic library that allows for authenticity and confidentiality across the entire Internet. Because the reported Heartbleed bug affects a vast number of internet services using OpenSSL to secure their services (such as HTTPS, SMTP, IMAPS, and POP3), a patched OpenSSL version was released by the maintainers within hours. Linux and UNIX distributions, which depend on the OpenSSL implementation, received patches by their respective upstream maintainers.

    SoundCloud too uses OpenSSL in many of our services to increase the security and privacy of our users. We therefore moved quickly to patch the vulnerability, and did so within hours of the patch being made available. We’ve also been in close communications with our vendors and service providers, to ensure that they have applied the appropriate fixes as well. We have confirmed that our implementations of OpenSSL are no longer vulnerable to this bug.

    Because we consider our users’ security and privacy of the utmost importance, we have further taken the precautionary measures to rotate SSL certificates and keys, and expire authentication tokens, such as session cookies, remember tokens, and OAuth access and refresh tokens. This means that users will be signed out of their SoundCloud accounts. Along with top security researchers and responsible companies, we have also recommended to our users that they change their passwords on all accounts (not just SoundCloud) that they have signed-in with in the past week. Developers of API clients that check our SSL fingerprints will need to update them.

    While the Heartbleed bug marks a sad day for the Internet as a whole, with SoundCloud’s rollout of Perfect Forward Secrecy (PFS) support last year, we ensured that the impact of an attack with the purpose of stealing private keys and reading previously encrypted traffic is minimized. In the same spirit we will also strive to find more such opportunities in the future and preemptively provide our users with the highest possible level of safety.

    For more details about this bug, go to heartbleed.com. To use tools to check your services, go to Filippo.io or FiloSottile/Heartbleed on GitHub.

  • March 8th, 2014 iOS Mobile Open Source Ruby Sponsoring CocoaPods By Erik Michaels-Ober

    CocoapodsI’m excited to announce that SoundCloud is sponsoring the development of CocoaPods through a Travis Foundation grant. CocoaPods is an open-source dependency manager for Objective-C projects. Travis Foundation is a non-profit that pairs corporate sponsors with open-source projects to make open source even better.

    At SoundCloud, our iOS team uses CocoaPods every day to manage the dependencies of our mobile apps. We hope that this sponsorship will lead to improvements that benefit the entire Mac and iOS developer ecosystem.

    Watch for updates in the coming weeks on the Travis Foundation blog and CocoaPods blog.

  • February 20th, 2014 JavaScript Smooth image loading by upscaling By Nick Fisher

    The site soundcloud.com is a single-page application that displays a multitude of users’ images. At SoundCloud, we use a technique to make the loading of an image appear smooth and fast. When displaying an image on screen, we want it to display to the user as fast as possible. The images display in multiple locations from a tiny avatar on a waveform to a large profile image. For this reason, we create each image in several sizes. If you are using Gravatar, this technique also applies because you can fetch arbitrarily-sized images by passing the desired size in a query parameter (?s=).

    avatar-tiny avatar-small avatar-medium avatar-large

    The technique uses the browser’s cache of previously loaded images. When displaying a large avatar image, first display a smaller version that is stretched out to full size. When the larger image has loaded, it fades in over the top of the smaller version.

    The HTML looks like this:

    <img class="placeholder" src="small.jpg" width="200" height="200">
    <img class="fullImage" src="large.jpg" width="200" height="200">
    

    The CSS looks like this:

    .fullImage {
      transition: opacity 0.2s linear;
    }
    

    For the sake of brevity, the positioning code is not included in the preceding snippet. However, the images should lie atop one another.

    Finally, the JavaScript code looks like this:

    var fullImage   = $('.fullImage'),
        placeholder = $('.placeholder');
    
    fullImage
      .css('opacity', 0)
      .on('load', function () {
        this.style.opacity = 1;
        setTimeout(placeholder.remove.bind(placeholder), 500);
      });
    

    Thus far, it’s not too complicated, and it gives a nice effect to the loading of images.

    But there’s a problem: we don’t want to make a request to get the small image just to display it for a few milliseconds. The overhead of making HTTP requests means that loading the larger image will usually not take significantly longer than the small one. Therefore, it only makes sense to use this technique if a smaller image has already been loaded during a particular session and thus served from the browser’s cache. How do we know what images are in cache? Each time an avatar is loaded, we need to keep track of that. However over time, there could be many thousands of avatars loaded within one session, so it needs to be memory efficient. Instead of tracking the full URLs of loaded images, we extract the minimum amount of information to identify a image, and use a bitmask to store what sizes have been loaded:

    // a simple map object, { identifier => loaded sizes }
    var loadedImages = {},
    
      // Let's assume a basic url structure like this:
      // "http://somesite.com/{identifier}-{size}.jpg" 
      imageRegex = /\/(\w+)-(\w+)\.jpg$/,
    
      // a list of the available sizes.
      // format is [pixel size, filename representation]
      sizes = [
        [ 20, "tiny"  ],
        [ 40, "small" ],
        [100, "medium"],
        [200, "large" ]
      ];
    
    // extract the identifier and size.
    function storeInfo(url) {
      var parts = imageRegex.exec(url),
          id    = parts[1]
          size  = parts[2],
          index;
    
      // find the index which contains this size
      sizes.some(function (info, index) {
        if (info[1] === size) {
          loadedImages[id] |= 1 << index;
          return true;
        }
      });
    }
    
    // once the image has loaded, then store it into the map
    $('.fullImage').load(function () {
      storeInfo(this.src);
    });
    

    When the image loads, we extract the important parts from the URL: namely, the identifier and the size modifier. Each size is mapped to a number—its index in the sizes array—and the appropriate bit is turned on in the loadedImages map. The code on line 27 does this conversion and bit manipulation; 1 << index is essentially the same as Math.pow(2, index). By storing only a single number in the object, we save quite a bit of memory. A single-number object could contain many different flags. For example, assume there are four different sizes and 10,000 images in the following map:

    asBools = {
      a: [true, true, false, true],
      b: [false, true, false, false],
      // etc...
    };
    
    asInts = {
      a: 11,  // 2^0 + 2^1 + 2^3 = 1 + 2 + 8
      b: 2,   // 2^1
      // etc...
    }
    

    The memory footprints of these objects differ by 30%: 1,372,432 bytes for the booleans, and 1,052,384 for the integers. The key names consume the largest portion of these objects’ memory. For this reason, it is important to compress the key names as much as possible. Numeric keys are stored particularly efficiently by the V8 JavaScript engine found in Chrome and Safari.

    We now have a map that shows us what images have been loaded during this session, and you can use that information to choose a placeholder:

    // find the largest image smaller than the requested one
    function getPlaceholder(fullUrl) {
      var parts = imageRegex.exec(fullUrl),
          id = parts[1],
          targetSize = parts[2],
          targetIndex;
    
      sizes.some(function (info, index) {
        if (info[1] < targetSize) {
          targetIndex = index;
          return true;
        }
      });
    
      while (targetIndex >= 0) {
        if (loadedImages[id] & 1 << targetIndex) {
          return fullUrl.replace(
            /\w+\.jpg$/,
            sizes[targetIndex][1] + '.jpg'
          );
        }
        --targetIndex;
      }
    }
    
    // and in usage:
    var placeholderUrl = getPlaceholder(fullSizeUrl);
    
    if (placeholderUrl) {
      // there has been a smaller image loaded previously, so...
      addTheFadeInBehaviour();
    } else {
      // no smaller image has been loaded so...
      loadFullSizeAsNormal();
    }
    

    Although, this technique is a bit involved and I’ve deliberately glossed over some of the details, it creates a nice visual effect, greatly reduces the perceived load time of the image, and it is especially effective for long-lived, single-page applications.

  • October 23rd, 2013 Android Hassle-free concurrency in Android using RxJava By Duana Stanley

    Both our Android and iOS teams use the reactive programming paradigm to simplify asynchronous, concurrent code in our native mobile apps. For Android, we use Netflix’s RxJava. Matthias Käppler—a SoundCloud engineer and a contributor to the RxJava Android libraryblogs about the HOWs and WHYs of RxJava on Android.

    Tomorrow in London, Matthias will be talking about RxJava at Droidcon. You can grab a drink with him and other members of our Android Team at the SoundCloud Droidcon Drinkup.