Im trying to achieve something similar to the first example under "Sending large amounts of data" at http://www.playframework.org/documentation/2.0/ScalaStream.
What I am doing differently is that I have more than one file that I want to concatenate in the response. It looks like this:
def index = Action {
val file1 = new java.io.File("/tmp/fileToServe1.pdf")
val fileContent1: Enumerator[Array[Byte]] = Enumerator.fromFile(file1)
val file2 = new java.io.File("/tmp/fileToServe2.pdf")
val fileContent2: Enumerator[Array[Byte]] = Enumerator.fromFile(file2)
SimpleResult(
header = ResponseHeader(200),
body = fileContent1 andThen fileContent2
)
}
What happens is that only the contents of the first file is in the response.
Something slightly simpler like below works fine though:
fileContent1 = Enumerator("blah" getBytes)
fileContent2 = Enumerator("more blah" getBytes)
SimpleResult(
header = ResponseHeader(200),
body = fileContent1 andThen fileContent2
)
What am I getting wrong?
I've got most of this from reading through the play code so I might have misunderstood, but from what I can see: the
Enumerator.fromFile
function(Iteratee.scala [docs][src]) creates an enumerator which when applied to anIteratee[Byte, Byte]
appends anInput.EOF
to the output of the Iteratee when it's done reading from the file.According to the Play! docs example that you linked to you're supposed to manually append an Input.EOF (alias of Enumerator.eof) at the end of the enumerator. I would think that, having an Input.EOF automatically appended to the end of the file's byte array is the reason that you're getting only one file returned.
The equivalent simpler example in the play console would be:
The fix, although I haven't tried this yet would be to go a few levels deeper and use the
Enumerator.fromCallback
function directly and pass it a custom retriever function that keeps returningArray[Byte]
s until all the files that you want to concatenate have been read. Refer to the implementation of thefromStream
function to see what the default is and how to modify it.An example of how to do this (adapted from
Enumerator.fromStream
):This is the play framework 2.2 code that I am using to play together a bunch of audio files one after another. You can see the use of a scala
Iterator
that gets converted to a javaEnumeration
forjava.io.SequenceInputStream
.The only problem with my code (in terms of what I am looking for) is that it is a stream meaning that I can't resume playing from a previous point in time even though I am sending the
CONTENT_LENGTH
. Maybe I am calculating the total length in a wrong way.The other issue with it is that the audio files need to be of the same type (expected), same amount of channels and same sample rate (took me a while to figure out), e.g all have to be ogg 44100Hz 2 channels.