I use this code to play decrypted audio on BlackBerry on the fly (for the sake of simplicity, I use TEA)
public void play(String path){
try {
FileConnection fc = (FileConnection) Connector.open(path, Connector.READ);
InputStream is = fc.openInputStream();
byte[] rawData = IOUtilities.streamToBytes(is);
processEncryptedAudio(rawData);
is.close();
fc.close();
}
catch (IOException ioex){
}
}
// TEA code is taken from http://www.winterwell.com/software/TEA.php
private void processEncryptedAudio(byte[] data) throws IOException {
TEA tea = new TEA("ABCDE ABCDE ABC A ABCDEF".getBytes());
byte[] decrypted_data = tea.decrypt(data);
ByteArrayInputStream stream = new ByteArrayInputStream(decrypted_data);
ByteArrayInputStreamDataSource source = new ByteArrayInputStreamDataSource(stream, "audio/mpeg");
try {
player = Manager.createPlayer(source);
player.start();
}
catch (MediaException me){
Dialog.alert("MediaException: "+me.getMessage());
}
}
The problem is decryption takes quite long time to finish. For example: on simulator, decrypting a 9 MB audio takes around 5 secs, but on BlackBerry Torch 9860 it takes more than 20 secs.
Is there any way to improve this? Actually the whole file doesn't neet to be encrypted, as long as it is obscured/cannot be played directly.
You could try switching from TEA to RC4, which is also very simple to implement and quite possibly faster.
Also, it looks like you're doing some unnecessary data copying: it would be slightly more efficient to make your decrypt() method modify the input byte array directly. This may require changing the calling code to skip some number of bytes at the beginning and/or end of the decrypted data, but that shouldn't be too hard. (The ByteArrayInputStream constructor can take optional offset and length arguments.)
If you want to get really fancy, you could try writing your own custom InputStream subclass that does the decryption "on the fly" while the audio is playing. If you use a block cipher in CTR, CFB or CBC mode (or ECB, but that's not secure), you can even make the stream seekable. If you want to be even fancier, make it a wrapper around the original InputStream so that you can do the loading, decryption and playing all at the same time.
Another option might be to use the RIM Crypto API, whose cipher implementations might be more efficient (possibly implemented in optimized native code) than your own. The Crypto API also already provides the DecryptorInputStream class which works in the manner I described above.
One possible down side is that the Crypto API seems to be only available to signed apps.
Related
I am uploading very large files, which exceed the available memory and thus I am using a FileBuffer as Receiver. Unfortunately, when uploading a large file, it takes very long to save it. Instead, I'd much rather start processing the file while it's still uploading.
So is there a way to receive the upload as a stream? Or could I implement my own Receiver, but then do I need to also implement my entire processing logic in that receiver?
Yes, you can implement your own Receiver; the built-in receivers like FileBuffer and MemoryBuffer are just helpers to cover basic use cases. The Receiver interface is simple:
public interface Receiver extends Serializable {
/**
* Invoked when a new upload arrives.
*
* #param fileName
* the desired filename of the upload, usually as specified by
* the client
* #param mimeType
* the MIME type of the uploaded file
* #return stream to which the uploaded file should be written
*/
OutputStream receiveUpload(String fileName, String mimeType);
}
Your task is to provide the OutputStream for the Upload component to write on; in the case of a FileBuffer, the class is creating a File object and a FileOutputStream. If you want to process the stream yourself, you can either extend FileOutputStream or create a custom OutputStream and implement the write method. A BufferedOutputStream is also a good option to investigate.
This is the code in Java to make the socket call, but I want to know how can I replicate this or something similar in iOS (Swift or Objective-C)
public String MakeSocketRequest() {
DataInputStream inputSt;
DataOutputStream outputSt;
Socket socket = new Socket(InetAddress.getByName("socketurl.io"), 40008);
String jsonStr = "{\"id\":1,\"method\":\"themethod\"}";
inputSt = new DataInputStream(socket.getInputStream());
outputSt = new DataOutputStream(socket.getOutputStream());
PrintWriter pw = new PrintWriter(outputSt);
pw.println(string);
Log.d("PrintWriter", jsonStr);
pw.flush();
BufferedReader bfr = new BufferedReader(new InputStreamReader(inputSt));
JSONObject json = new JSONObject(bfr.readLine());
Log.d("Json", json.toString());
inputSt.close();
outputSt.close();
return json.toString();}
If you want to do it natively without 3rd-party libraries,
then you can use CFStreamCreatePairWithSocketToHost function to create input and output streams (no socket object is needed).
Here's some example code to set this up
And the search shows many more
On iOS you can't write or read the streams immediately, and you have to wait until the socket is connected, and you get a permission to read/write. This is done by implementing NSStreamDelegate.
If you get NSStreamEventHasSpaceAvailable event there, you can write your string to the output stream. You don't need a PrintWriter to just write a string, because it is easy to convert NSString to NSData, and write NSData.
If you get NSStreamEventHasBytesAvailable event, means you can try to read data from the input stream to some buffer (like NSMutableData). There's no builtin BufferedReader with a readLine method, so you will have to buffer the data yourself and detect when a new line character appears there. After that you can cut a part of the buffer until the new line, and convert NSData to NSString (or a JSON object by using NSJSONSerialization).
Note: scheduleInRunLoop calls might look confusing, but they are required to start receiving events via the delegate. It kind of tells the system on which thread you want to receive them.
P.S. I agree with commenters that if you have control over the server code, it's better to use a standard protocol like Socket IO or msgpack instead of inventing your own, because they have better and nicer libraries and wider community support.
After searching around the net, I couldn't find a method to download a mp3 from a server, save it in the local storage (iPad) and then load and play it other than converting it to byteArray, saving it as .mp3 and then load it and read it back to mp3 to be able to play it in the flash application.
The problem is, although this method works fine, the uncompressed files (in byteArray format) saved in the local storage are too heavy and I suspect that the app is wasting memory.
My question is, is there any form of saving the mp3 directly, without any conversion, like a properly playable mp3? I can't use methods like download() or save() from FileReference.
Lots of thanks!!
SOLUTION!! (WORKING PERFECTLY):
I continued looking for a method to do it around the net, and some forums gave me a clue to do whick I was searching. It was finally pretty simple, but I spent almost 2 weeks to find it out... here is my code:
var queue:LoaderMax = new LoaderMax({name:"mainQueue", onProgress:progressHandler, onComplete:completeHandler, onError:errorHandler});
queue.append( new DataLoader("http://" + **url**, {name:**"example.mp3"**format:"binay"}));
queue.load();
// Complete Event:
private function completeHandler():void {
var file:File = new File(**your location**); // appData
var fr:FileStream = new FileStream();
fr.open(file.resolvePath(nameIn), FileMode.WRITE);
fr.writeObject(LoaderMax.getContent("example.mp3"));
fr.close();
fr = null;
// Now the mp3 is saved in local storage, we load it as Sound object so we can play it.
var loader:MP3Loader;
loader = new MP3Loader(**your location**, {autoPlay:false}) ;
loader.addEventListener(Event.COMPLETE, function():Sound {
loader.content.play(); // This line is the only one not checked, but I am completely sure you can do something like this to play the sound. For example, I introduce the loader.content in a Array of Sound and later I am capable to play any sound I want.
loader.dispose(true); // This is very important to free memory. You should do the same thing with queue when all items are downloaded.
});
loader.load();
}
I expect this help a lot of people!!
I'm developing a radio app for BB 5.0 in java. I don't find a way to play the radio from the url stream address that I have. I use multiple formats but nothing works (.pls, .aac, .m3u). I get a RuntimeException every time I try to play the stream. The content is ok, I've checked it.
InputStream stream = Connector.openInputStream(urlPlay);
StreamConnection streamConnection = (StreamConnection) Connector.open(urlPlay, Connector.READ);
InputStream readAhead = streamConnection.openDataInputStream();
byte[] audioData = new byte[500];
readAhead.read(audioData,0,audioData.length);
ByteArrayInputStream in2 = new ByteArrayInputStream(audioData);
player = javax.microedition.media.Manager.createPlayer(in2, "audio/aac");
System.out.println("REALIZE");
player.realize();
System.out.println("PREFETCH");
player.prefetch();
System.out.println("START");
player.start();
Edit:
When I use a URL from my .pls file I hear a little bit of my streaming but It stops immediately.
I suspect the problem is that you are trying to play playlist files instead of an actual stream. Generally, you need to parse those files yourself to get the real stream URLs.
If you open up that .m3u file, you will see that it is just a list of URLs. Take one of those URLs and then try it. Also, be sure you are setting the right content type. You can determine what that type is with cURL or VLC.
Can anyone suggest how to handle a slow network when streaming video in a web view?
When the network strength is poor, a blank screen appears or video doesn't stream.
Is there a way to detect this condition so that we can alert the user? (Apart from using private API.)
Perhaps ifi_baudrate member of the if_data structure (declared in <net/if.h>) is what you need. If baudrate is less than some threshold value, then you can show an alert.
Please see the following answer to know how to obtain the if_data structure for a particular network interface:
https://stackoverflow.com/a/8014012/1310204
You can easily detect the state of the network connection via the HTML5 networking API
http://www.html5rocks.com/en/mobile/optimization-and-performance/#toc-network-detection
Also if you want to test the network speed, just set up some files on your server of a specific size, and do a ajax request for the file, while timing how long it takes to download.
You can use a simple:
var start = new Date();
$.get("someFile.jpg")
.done(function() {
var elapsed = (new Date() - start);
});
Or dig into the HTML5 performance API:
http://www.html5rocks.com/en/tutorials/webperformance/basics/
...if you not using javascript, the same applies. Just open a network connection with whatever is at your disposition, download a small file & do the math ;-)