This post provides links to the live stream only. For more details on the whole process, see the previous post.
To listen to the live stream, tap on one of the following links:
This post provides links to the live stream only. For more details on the whole process, see the previous post.
To listen to the live stream, tap on one of the following links:
In my last post, I described how I’m trying to use streaming audio to deliver simultaneous translation of the messages at my church. This post is meant to be a HOWTO for anyone attending and tho want to listen to the stream.
Note for this to work, you will need to be connected to the appropriate wireless network. This will be given out on Sunday morning
Once you have created and saved the custom URL, each time you want to listen you can just select that Custom URL from the favorites list and it will begin streaming the audio.
When we moved to Cluj, we started attending a local church, Casa Tamplarului. As a church, it reminds us a lot of National Community Church in DC, which we attended before we moved here. Of course, being the audio nerd that I am, I’ve joined the production team and now run front of house regularly.
As much as I like the church and the people there, I have one issue: the message is delivered in Romanian. Actually, it’s not a problem with the church, but it’s really my problem as my Romanian isn’t quite as far along as I would like. I’m learning, but I’m not there yet.
In talking with some of our friends there, the team has wanted to offer simultaneous translation of the service into English for a while. They even started collecting some consumer-grade wireless headphones to try and use. While we were able to make them function, they offer some limitations, so we started looking at alternatives.
What we’ve settled on as an initial trial is to use mobile phones and streaming audio as a delivery platform. It offers a few key advantages:
For the initial pilot, we started with a completely local setup with the following components:
One key thing I did was to wire up everything that was static. Both laptops were wired into a gigabit desktop switch in order to limit the amount of traffic on the wireless network. We also did not connect the access point to the Internet, mostly because it was an initial test, however, as I’m thinking about it now, we may not want to connect it to the internet at all, again in order to limit saturating the wireless network.
In the end, with just me connecting, the technology did work. There is a fairly long delay of about 10-15 seconds in the audio stream. I think this is due to the client buffering the audio. I will continue to look into how to reduce that latency, but for now it’s workable.
We plan on trying it again this weekend with a larger audience of clients and see how it goes. We also need to gather together some additional upstream tech (microphones, mixers, etc) in order to complete the rig.
I also plan on updating things here as we get closer to a finished solution and start learning lessons of what to do and what not to do.
class LeakyAbstraction
{
int makeMeFail()
{
Random r = new Random()
if(r.nextBoolean())
return -1
// Here’s a “hidden” type conversion error
}
}
// A sample Groovy script
a = 1
def b = 2
def doSomething()
{
def c = "Foo"
def d = a
}
// A cross compiled Groovy script
public class Sample extends Script {
// Groovy-specific constructors omitted
public static void main(String[] args) {
new Sample(new Binding(args)).run();
}
public Object run() {
setProperty("a", 1);
Integer b = 1;
return null;
}
public void doSomething() {
String c = "Foo";
Object d = this.getBinding().getProperty("a");
}
}
class Worker implements Runnable
{
public void run()
{
// Work goes here
}
}
class Parent
{
static void main(String[] args)
{
// Create the worker object
Worker w = new Worker();
// Create the new thread
Thread t = new Thread(w);
// Start the thread
t.start();
// Wait for the thread to complete processing
t.join();
}
}
public class Example
{
synchronized void mutexMethod()
{
// Only one thread can execute this code
// at a time
}
void method()
{
synchronized(this)
{
// This code block is mutex
}
}
}
// Wait code in one thread
synchronized(obj)
{
obj.wait()
}
// Send signal code in separate object
synchronized(obj)
{ obj.notify()
}
while(true)
{
// Break when the first true is returned
if(new Random().nextBoolean())
break;
}
switch(1)
{
case 1:
// Do something and then exit
break;
case 2:
case 3:
// Case 2 falls through to case 3
default:
// Case 2 and 3 will fall through
}
outermost:
for(int i = 0; i < 10; i++)
{
for(int j = 0; j < 10; j++)
{
if(i < 5 && i + j == 17)
break;
if(i + j == 17)
break outermost
println "${i},${j} = ${i+j}"
}
}
for(int i = 0; i < 10; i++)
{
if(i % 2 == 0)
continue;
println i
}
try
{
}
catch(ExceptionTypeOne e1)
{
// code do deal with ExceptionTypeOne and any subclasses
}
catch(ExceptionTypeTwo e2)
{
// code do deal with ExceptionTypeTwo and any subclasses
}
finally
{
// code to be executed at the end of the block regardless
// of outcome (successful or exceptional completion)
}
// The following method throws a FileNotFoundException
void method() throws FileNotFoundException
{
// The following call throws a FileNotFoundException
// and must be declared or caught
FileInputStream fis = new FileInputStream(“foo”)
// Attempt to read data from fis
try
{
// throws an IO exception, caught below
int byte = fis.read()
}
catch(IOException e)
{
// Rethrow the exception as a runtime exception
// which does not need to be declared
throw new RuntimeException(“Failed reading”)
}
finally
{
try
{
fis.close()
}
catch(IOException ex)
{
throw new RuntimeException(ex)
}
}
}
abstract class Shape
{
private int x, y
public int getX() { return x }
public int getY() { return y }
public void setX(int x) { this.x = x }
public void setY(int y) { this.y = y }
abstract void draw()
}
class Circle extends Shape
{
private long radius
void draw()
{
println "I drew a circle @ ${x},${y} "+
"with radius ${radius}"
}
}
class Test
{
static void main(String[] args)
{
// Create instance of Circle
Circle c = new Circle()
c.radius = 1.4
// Access the methods from Shape
c.x = 1
c.y = 5
// Assign c to a variable of type
// Shape which works because Circle
// is a sub class of Shape
Shape s = c
s.draw()
}
}
trait FlyingAbility
{
String fly() { "I'm flying!" }
}
class Bird implements FlyingAbility {}
def b = new Bird()
assert b.fly() == "I'm flying!"
trait A
{
String exec() { 'A' }
}
trait B
{
String exec() { 'B' }
}
// When called, the exec command will return the value of
// B.exec() because it is listed last
class C implements A, B {}
class Circle
{
private int x, y
private float radius
void draw()
{
println "I drew a circle @ ${x},${y} "+
"with radius ${radius}"
}
void draw(int scale)
{
int x = this.x * scale
int y = this.y * scale
float radius = this.radius * scale
println "I drew a circle @ ${x},${y} "+
"with radius ${radius}"
}
}
class CastExample
{
static void main(String[] args)
{
// Compile time-check
Parent p = getChild();
// Runtime check
Child c = (Child)getParent();
// Invalid cast
Child c = new Object()
}
static Parent getParent()
{
// Child is cast to Parent on return
return new Child();
}
static Child getChild()
{
return new Child();
}
}
class Parent
{
// No implementation for this example
}
class Child extends Parent
{
// No implementation for this example
}
String s = “42”
int i = s as Integer
short s = 10
int i = s
long i = s
ArrayList old = new ArrayList();
old.add(“A string”);
// The required cast to use the stored object as a String
String aString = (String)old.get(0);
ArrayList<String> generic = new ArrayList<String>();
generic.add(“a string”);
// Accessing an element from a generic does not require
// the cast operation
aString = generic.get(0);
Groovy inherits this Java generics behavior directly, allowing the developer to use the Java generics.
def list = new ArrayList<String>() as ArrayList<String>
list.add(/a string/)
String value = list.get(0)
class GroovyGenericClass<T>
{
private ArrayList<T> items = new ArrayList<T>()
void add(T t)
{
items.add(t)
}
}
// Require any class used in the generic to extend
// Comparable (in this case Comparable is an interface
// so the class must implement it)
class GroovyGenericClass<T extends Comparable>
{
private ArrayList<T> items = new ArrayList<T>()
void add(T t)
{
items.add(t)
}
boolean equals(int index, T t)
{
// The compareTo method is defined in the
// interface Comparable
return items.get(index).compareTo(t) == 0
}
}
public class JavaClass
{
// This is a private variable only accessible
// by instances of this class
private int privateInt;
private int anotherPrivateInt = 42;
// The following are getters and setters to provide
// access to the private variable
public int getPrivateInt()
{
return privateInt;
}
public void setPrivateInt(int value)
{
this.privateInt = value;
}
}
class GroovyClass
{
private int privateInt
}
class GroovyExecutableClass
{
static void main(String[] args)
{
JavaClass jc = new JavaClass()
jc.setPrivateInt(3)
println(jc.getPrivateInt())
// Accessing the private variable by the
// automatic getter/setter
GroovyClass gc = new GroovyClass()
gc.privateInt = 4
println(gc.privateInt)
// Note: Groovy automatically provides the
// same functionality for existing Java classes
println(jc.anotherPrivateInt)
}
}
class AnotherExample { private int index; private String name; // Remember, Groovy is public by default String toString() { return name + ":" + index; } }In addition to class-based methods, Groovy also offers a type of standalone function. This function can also encapsulate a set of operations and be reused. The function is not bound to a class, but instead is bound to the script itself, creating a form of JavaScript-like closure. The function can be bound to a variable and passed into a function for the purposes of callbacks or other instances where a dynamic function needs to be provided to a method.
def callback(def value) { println(value) } def needsCallback(Closure c) { c(“do something”) } // Note the use of this to reference the callback // in the script context needsCallback(this.&callback)Note: in Groovy a stand-alone function is called a closure.
class Example { void properProcedure(int param1, String param2) { // do something } int functionalProcedure(int param1, String param2) { // do something and return a value return 0; } }
int i = 0
short s = 4
// Define a composite as an array
def comp = [1,2,3]
// Selective update
comp[2] = 4
// Total update
comp = [5,6,7]
int a = 1 def b = c = 2
boolean comparison = new Random().nextBoolean() if(comparison) { println "Value was true" } else { println "Value was false" }Groovy also supports the nested if-else if-else structure.
boolean comparison = new Random().nextBoolean() boolean comparison2 = new Random().nextBoolean() if(comparison && comparison2) println "Both are true" else if (comparison && !comparison2) println "Only comparison is true" else if (!comparison && comparison2) println "Only comparison2 is true" else println "Both were false"
def x = 1.23 def result = "" switch ( x ) { case "foo": result = "found foo" // let’s fall through case "bar": result += "bar" case [4, 5, 6, 'inList']: result = "list" break case 12..30: result = "range" break case Integer: result = "integer" break case Number: result = "number" break case ~/fo*/: result = "foo regex" break case { it < 0 }: // or { x < 0 } result = "negative" break default: result = "default" } assert result == "number"
// Definition // while(<termination>) // { // statement(s) // } // Example def i = 0 while(i < 10) { println i++ }
// Prototype // for(<initialization>;<termination>;<increment>) // { // <statements> // } // Example for(int i = 0; i < 10; i++) { println i } def j = 0; // Example for(; j < 10;) { println j++ }One item to note is that as of 2.4, Groovy for loops only support a single initialization parameter in a for loop, while Java can support multiple. Groovy version 2.6 will offer this functionality.
// Definition // for( <type> <variable> in/: <array/list>) // { // statement(s) // } // Example using the word in for(int j in [0,1,2,3,4,5,6,7,8,9]) { println j } // Example using the : instead of in for(int j : [0,1,2,3,4,5,6,7,8,9]) { println j }
// Definition // <array/list/map>.each(Closure c) // Print 0-9 [0,1,2,3,4,5,6,7,8,9].each { println it } // Get the index and letter from the list ["Alpha","Bravo","Charlie","Delta","Echo"].eachWithIndex { letter, index -> println "${index} -> ${letter}" } // Iterate through a map, using the variable letter for key // and name for word [ "A":"Alpha", "B":"Bravo", "C":"Charlie", "D":"Delta", "E":"Echo"].each{ letter, name -> println "${letter} <-> ${name}" }Because closures can be bound to variables, this can allow for more compact coding through the reuse of closures on multiple each or eachWithIndex calls.
// Define the closure def doSomething(letter,index) { println "${index} -> ${letter}" } ["Alpha","Bravo","Charlie","Delta","Echo"] .eachWithIndex this.&doSomething ["Foxtrot","Golf","Helo","India","Juliet"] .eachWithIndex this.&doSomething
if(getCurrentState())
{
}
int binaryLiteral = 0b110101 int octalLiteral = 07189 int base10Literal = 12229 int hexLiteral = 0x1AC4 float decimalLiteral = 1.234In addition to simple numerical definition, Groovy inherits Java’s support for including underscores in a long number for readability (eg: int a = 123_456_789). It also supports forcing numbers to a specific type by using suffixes:
Type | Suffix |
BigInteger | G or g |
Long | L or l |
Integer | I or i |
BigDecimal | G or g |
Double | D or d |
Float | F or f |
String aString = 'a single quoted string'Double quoted strings are literals that are:
String aString = "a double quoted string"Triple quoted strings are literals that are:
String aString = '''First line
A second line
A third line\
continued '''Slashy strings are literals that are:
String aString = /.*foo.*/Dollar slashy strings are literals that are:
def dollarSlashy = $/ Hello $name, today we're ${date}. $ dollar sign $$ escaped dollar sign \ backslash / forward slash $/ escaped forward slash $$$/ escaped opening dollar slashy $/$$ escaped closing dollar slashy /$String escape sequences:
Character | Meaning |
\t | tabulation |
\b | backspace |
\n | newline |
\r | carriage return |
\f | Form feed |
\\ | backslash |
\ | single quote (for single quoted and triple single quoted strings) |
\" | double quote (for double quoted and triple double quoted strings) |
\u#### | a Unicode character |
// Create an array in Groovy def array = [1,2,3] array << 4It is possible to coerce Groovy into creating a literal, fixed-length array (ie: <type>[]) either by defining it as the specific data type or using the keyword as.
// Defined as a fixed size int primitive array int[] intArray = [1,2,3] // Defined internally as a fixed size long primitive // array def longArray = [1,2,3] as long[]In addition to single-dimensional arrays, Groovy allows for creating multi-dimensional arrays.
def multiDim = [[1,2,3],[4,5,6]]Defining a value in Groovy is accomplished in a similar method to Java, C or C++.
// Example variable definitions in Groovy // datatype variablename (= optionalvalue) def name = “A name” int i = 0 long l = 123Maps are created using the following notation:
// Define a map with three key-value pairs def colors = [red:'FF0000', green:'00FF00', blue: '0000FF']
Operators | Precedence |
Postfix | expr++ expr-- |
Unary | ++expr --expr +expr -expr ~ ! |
Multiplicative | * / % |
Additive | + - |
Shift | << >> >>> |
Relational | < > <= >= instanceof |
Operator | Precedence |
Equality | == != |
bitwise AND | & |
bitwise exclusive OR | ^ |
bitwise inclusive OR | | |
logical AND | && |
logical OR | || |
Ternary | ? : |
// Example find def text = "some text to match" def m = text =~ /match/ assert m instanceof Matcher if (!m) { throw new RuntimeException("Oops, text not found!") }
// Example match
m = text ==~ /match/ assert m instanceof Boolean if (m) { throw new RuntimeException("Should not reach that point!") }
class Foo { int val; } Foo f = new Foo()
// Dot notation for accessing members of an object f.val = 7 // Define a map with three key-value pairs def colors = [red:'FF0000', green:'00FF00', blue: '0000FF'] // Accessing the values can occur using the [] // notation or by the "." notation assert colors['red'] == 'FF0000' assert colors.green == '00FF00'Groovy offers an additional variable access operator called the safe navigation operator. This allows for accessing an object reference that may, or may not, have been defined.
def person = Person.find { it.id == 123 } def name = person?.name assert name == null
Type | Description |
boolean | A data type representing 21 values (programmatically defined as true and false) |
byte | An 8-bit number from -128 to 127 inclusive |
char | A single 16-bit Unicode character with values from \u0000 to \ufff inclusive |
short | A 16-bit signed integer with values from -32,768 to 32,767 inclusive |
int | A 32-bit signed integer with values from -231 to 231-1 inclusive |
long | A 32-bit signed integer with values from -263 to 263-1 inclusive |
float | A single-precision 32-bit IEEE 754 floating point number |
double | A double-precision 64-bit IEEE 754 floating point number |
def a = 1
assert a instanceof Integer
// Integer.MAX_VALUE
def b = 2147483647
assert b instanceof Integer
// Integer.MAX_VALUE + 1
def c = 2147483648
assert c instanceof LongIt should be noted that a variable defined using the def keyword is stored not as a primitive, but as the corresponding Java object.
enum DefinedPrimitive { VALUE1, VALUE2, VALUE3 }