SoundCloud for Developers

Discover, connect and build

Backstage Blog RSS

  • April 27th, 2014 Contests Search and Discovery Irrational Fun: Find Yourself at Berlin Buzzwords By Erik Michaels-Ober

    We were counting down the days until Berlin Buzzwords on May 25, when we realised that it would be great if you came too! With that in mind, we've created a contest. One lucky winner will receive a free ticket to Berlin Buzzwords, including travel expenses and accommodation. Here are the details about how to apply.


    The ratio of a circle's circumference to its diameter, represented by the Greek letter π, is an irrational number—it never terminates or repeats. Your goal is to find the SoundCloud logo in π.

    We have provided a 14 pixel by 6 pixel, greyscale reference image:

    Here is the same image at 60X magnification:

    Each of the 10 shades of grey in this image can be mapped to a number:

    Color RGB Hex Number
      ffffff 0
      f0f0f0 1
      ebebeb 2
      d0d0d0 3
      c1c1c1 4
      a8a8a8 5
      878787 6
      535353 7
      333333 8
      000000 9

    Applying this mapping to the reference image produces the following 84-digit bitmap:

    0 0 0 0 0 3 3 9 9 9 6 0 0 0
    0 0 0 3 4 9 5 9 9 9 9 4 0 0
    0 1 2 7 5 9 5 9 9 9 9 7 1 0
    3 9 5 9 5 9 5 9 9 9 9 9 9 3
    6 9 5 9 5 9 5 9 9 9 9 9 9 6
    1 8 5 9 5 9 5 9 9 9 9 9 8 1
    

    Your challenge is to write an algorithm that finds the 10 sequences that most closely approximate the reference image. Each result should include the sequence and its position (after the decimal point) in π.

    Here is an example result set:

    Rank Image Sequence Offset
    1 082201638940102393659252475011295776958920 282336494898427768768699465405437965994582 297,640,119
    2 310015049916890341096198545241549627773525 291969856827158758552799587406476458977970 792,987,187
    3 212021479960265330123798820231693768599316 147634474729776147987653958935291919768971 972,165,010
    4 000053743536020032496985553181128909983810 344939134894807349584729687746183109884672 981,165,566
    5 142204297650171312983445842322141909755200 787408739757838589593329762648444919386594 789,652,974
    6 300011495970664010077917573663456957498854 662995598898697947677549686339433357728071 197,342,990
    7 313560984264300011495970664010077917573663 456957498854662995598898697947677549686339 197,342,978
    8 870402479996214234001557832923050859979903 649788689695954439755933903629798966788984 75,975,342
    9 208503759370245135490877462200175839969750 453766432680245845143285985661373828688970 343,577,393
    10 300544295771128716836756973814286978997516 282647269986574856578306678421894769876141 950,462,734

    Entries will be judged against the follow criteria:

    • Code quality
    • Runtime performance
    • Visual closeness to the reference image (subjective)


    You should run your algorithm against the following data set (approximately 1 GB), which contains the first 1,000,000,000 (billion) digits of π.

    Please send your submission, including a link to the source-code repository, to e@soundcloud.com on or before May 5, 2014 23:59 UTC. Your repository should contain a README that includes instructions about how to set up and run your code. Entries are subject to the terms and conditions.


    UPDATE

    Congratulations to Tomasz Pewiński, who submitted the winning entry.

    We’d also like to acknowledge entries by Dan Oved and Martin Kühl, which were also excellent. Thanks to everyone else who participated in the contest. We hope it was fun!

  • 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.