DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Coding
  3. Languages
  4. Binary Websockets with Play 2.0 and Scala

Binary Websockets with Play 2.0 and Scala

Jos Dirksen user avatar by
Jos Dirksen
·
May. 08, 12 · Interview
Like (0)
Save
Tweet
Share
4.69K Views

Join the DZone community and get the full member experience.

Join For Free

in a recent article i showed how you can use webrtc, canvas and websockets together to create a face detection application whose frontend runs completely in the browser, without the need for plugins. in that article i used a jetty based backend to handle the image analysis using opencv through the javacv wrapper.
when i almost finished the article, i noticed that websockets is also supported from play 2.0. i really like developping in play and in scala so as an experiment i rewrote the backend part from a jetty/java/javacv stack to a play2.0/scala/javacv stack. if you want to do this for yourself, make sure you start with the frontend code from here . since the frontend code hasn't changed except the location where the websockets are listening.

setting up the play 2.0 environment

i'm not going to talk too much about how to start a play 2.0/scala project. you can find the details in some of my other posts should you need more information. what we do need to do, is setup the dependencies for javacv so that they can be used from play 2. i've manually added them to my local ivy repository, so that i can reference them from the sbt configuration like any other dependency. for my example i created the following directory layout for the javacv libraries:

./play-2.0-rc2/repository/cache/javacv
./play-2.0-rc2/repository/cache/javacv/javacpp
./play-2.0-rc2/repository/cache/javacv/javacpp/ivy-2.3.1.xml
./play-2.0-rc2/repository/cache/javacv/javacpp/ivydata-2.3.1.properties
./play-2.0-rc2/repository/cache/javacv/javacv
./play-2.0-rc2/repository/cache/javacv/javacv/ivy-2.3.1.xml
./play-2.0-rc2/repository/cache/javacv/javacv/ivydata-2.3.1.properties
./play-2.0-rc2/repository/cache/javacv/javacv-macosx-x86_64
./play-2.0-rc2/repository/cache/javacv/javacv-macosx-x86_64/ivy-2.3.1.xml
./play-2.0-rc2/repository/cache/javacv/javacv-macosx-x86_64/ivydata-2.3.1.properties
./play-2.0-rc2/repository/local/javacv
./play-2.0-rc2/repository/local/javacv/javacpp
./play-2.0-rc2/repository/local/javacv/javacpp/2.3.1
./play-2.0-rc2/repository/local/javacv/javacpp/2.3.1/ivys
./play-2.0-rc2/repository/local/javacv/javacpp/2.3.1/ivys/ivy.xml
./play-2.0-rc2/repository/local/javacv/javacpp/2.3.1/jars
./play-2.0-rc2/repository/local/javacv/javacpp/2.3.1/jars/javacpp.jar
./play-2.0-rc2/repository/local/javacv/javacv
./play-2.0-rc2/repository/local/javacv/javacv/2.3.1
./play-2.0-rc2/repository/local/javacv/javacv/2.3.1/ivys
./play-2.0-rc2/repository/local/javacv/javacv/2.3.1/ivys/ivy.xml
./play-2.0-rc2/repository/local/javacv/javacv/2.3.1/jars
./play-2.0-rc2/repository/local/javacv/javacv/2.3.1/jars/javacv.jar
./play-2.0-rc2/repository/local/javacv/javacv-macosx-x86_64
./play-2.0-rc2/repository/local/javacv/javacv-macosx-x86_64/2.3.1
./play-2.0-rc2/repository/local/javacv/javacv-macosx-x86_64/2.3.1/ivys
./play-2.0-rc2/repository/local/javacv/javacv-macosx-x86_64/2.3.1/ivys/ivy.xml
./play-2.0-rc2/repository/local/javacv/javacv-macosx-x86_64/2.3.1/jars
./play-2.0-rc2/repository/local/javacv/javacv-macosx-x86_64/2.3.1/jars/javacv-macosx-x86_64.jar

as you can see from this listing, i just added the three javacv supplied jars to my local repository. i also added a minimal ivy.xml so that they can be used from ivy and sbt. this minimal ivy.xml looks like this:

<?xml version="1.0" encoding="utf-8"?>
<ivy-module version="2.0" xmlns:m="http://ant.apache.org/ivy/maven">
    <info
        organisation="javacv"
        module="javacv-macosx-x86_64"
        revision="2.3.1"
        status="release">
        </info>
 
        <publications>
            <artifact type="jar"/>
        </publications>
</ivy-module>

with these files added to my repository i can setup the dependencies for the play 2.0 project in the build.scala file.

import sbt._
import keys._
import playproject._
 
object applicationbuild extends build {
 
    val appname         = "playwebsocketjavacv"
    val appversion      = "1.0-snapshot"
 
    val appdependencies = seq(
      "javacv" % "javacv" % "2.3.1",
      "javacv" % "javacpp" % "2.3.1",
      "javacv" % "javacv-macosx-x86_64" % "2.3.1"
    )
 
    val main = playproject(appname, appversion, appdependencies, mainlang = scala).settings(
      // add your own project settings here      
    )
}

now run "play update" and "play eclipsify" to update the dependencies and your eclipse configuation (if you're using eclipse that is).

configure websockets in play

using websockets in play 2.0 is very easy. the first thing you need to do is add the url to your routes configuration in the conf directory.

get     /wsrequest                  controllers.application.wsrequest

and, of course, you need to implement the action this route points to:

/**
 * simple websocket listener configured in play 2. this uses a synchronous model, where
 * the same channel is used to send the response. for this usecase this is useful, if
 * we want async processing we could have used akka actors together with play 2.0 async
 * support.
 */
def wsrequest = websocket.using[array[byte]] { request =>
 
  // create the outbound value that is called for each
  val out = enumerator.imperative[array[byte]]();
 
 val in = iteratee.foreach[array[byte]](content => {
	   out.push(facedetect.detect(content));
  })
 
  // tie the in and out values to each other
  (in, out)
}

in this code we configure an input channel (in), and an output channel (out) and connect them to the socket. whenever the html5 client sends a request over the websocket our "in" method is called, and when we want to send something to the client we can use the "out" channel. the "in" channel needs to be defined as an iteratee (more info see these play docs). what this does is, that for each input message we receive we run the specifici method. in this case we run the facedetect.detect operation (more on this later) and the result from this operation is pushed back to the client using the "out" channel. this "out" channel itself is defined as an enumerator (see these play docs). we can attach different listeners if we want to this enumerator, but in this case we don't do anything with the message, just pass it along to the client.

using javacv from scala

the last step is the code of the facedetect.detect function. the java version, see earlier mentioned article , is very easily converted to a scala one.

package javacv
 
import com.googlecode.javacv.cpp.opencv_core._
import com.googlecode.javacv.cpp.opencv_imgproc._
import com.googlecode.javacv.cpp.opencv_highgui._
import com.googlecode.javacv.cpp.opencv_objdetect._
import com.googlecode.javacpp.bytepointer
import java.nio.bytebuffer
import javax.imageio.imageio
import java.io.bytearrayoutputstream
import scala.tools.nsc.io.virtualfile
 
object facedetect {
 
	var cascade_file =path_to_cascade_file;
  	var minsize = 20;
	var group = 0;
	var scale = 1.1;
 
  def detect(imagedata:array[byte]) : array[byte] = {
 
    // we need to wrap the input array, since bytepointer doesn't accept
    // a bytearray as input. it accepts a byte varargs, but array[byte]
    // doesn't convert automatically
    var wrappeddata = bytebuffer.wrap(imagedata);
    var originalimage = cvdecodeimage(cvmat(1, imagedata.length,cv_8uc1, new bytepointer(wrappeddata)));
 
    // convert to grayscale for easy detection
    var grayimage = iplimage.create(originalimage.width(), originalimage.height(), ipl_depth_8u, 1);
    cvcvtcolor(originalimage, grayimage, cv_bgr2gray);
 
    // storage is needed to store information during detection
	var storage = cvmemstorage.create();
 
	// load and run the cascade
	var cascade = new cvhaarclassifiercascade(cvload(cascade_file));
	var faces = cvhaardetectobjects(grayimage, cascade, storage, scale, group, minsize);
 
	// draw a rectangle for the detected faces
	for (i <- 0 until faces.total) {
	  var r = new cvrect(cvgetseqelem(faces, i));
	  cvrectangle(originalimage, cvpoint(r.x, r.y),
					cvpoint(r.x + r.width(), r.y + r.height),
					cvscalar.yellow, 1, cv_aa, 0);
	}
 
	// convert to bytearray and return
	var bout = new bytearrayoutputstream();
	var imgb = originalimage.getbufferedimage();
	imageio.write(imgb, "png", bout);
 
    bout.tobytearray()
  }
}

the only issue i ran into was with the bytepointer constructor. one of the signatures accepts a varargs of the type byte. in java this allows me to just supply this constructor with a byte[], in scala however this doesn't work. luckily though, a bytepointer can also be created using a bytebuffer. for the rest this is a one-to-one conversion of java to scala.

running the code

and that's almost it. by default play listens on port 9000, in the jetty based example we had the server running on 9999 and listening to the root context. to work with our play2/scala based server we just need to point the browser to the correct websocket server url.

 ws = new websocket("ws://127.0.0.1:9000/wsrequest");

and now, when we run it, we use play 2 as our server and run the javacv code using scal. and more importantly it still works:

javacv from scala and play 2.0

WebSocket Scala (programming language)

Published at DZone with permission of Jos Dirksen, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Benefits and Challenges of Multi-Cloud Integration
  • What “The Rings of Power” Taught Me About a Career in Tech
  • MongoDB Time Series Benchmark and Review
  • How to Use Buildpacks to Build Java Containers

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: