Android streaming from icecast server get track information - android

I have a stream from an icecast server downloading, and I can grab the information in the headers by doing the following:
URLConnection cn = new URL(mediaUrl).openConnection();
cn.connect();
int pos=1;
String x;
String y;
while (cn.getHeaderField(pos) != null)
{
x=cn.getHeaderFieldKey(pos);
y = cn.getHeaderField(x);
Log.e(":::::",""+x+" : "+y);
pos++;
}
When I do this all of the headers I receive are shown as:
content-type : audio/mpeg
icy-br : 64
ice-audio-info : ice-samplerate=22050;ice-bitrate=64;ice-channels=2
icy-br : 64
icy-description : RadioStation
icy-genre : Classical, New Age, Ambient
icy-name : RadioStation Example
icy-private : 0
icy-pub : 1
icy-url : http://exampleradio.com
server : Icecast 2.3.2
cache-control : no-cache
However if I open my stream in mplayer I get:
ICY Info: StreamTitle='artist - album - trackname'
and with each time the song is changed, the new track information is sent appearing the same way in mplayer.
In android when I attempt to read the icy-info all I get returned is null. Also how would I go about retrieving the new information from the headers while I am buffering from the stream? Because even if I try to read the header of something I already know exists whilst buffering such as:
Log.e(getClass().getName()," "+cn.getHeaderField("icy-br"));
All I get returned is null.
I hope this makes sense, I can post more code on request.

I realize this question is old, but for others who are facing this challenge, I am using this project: http://code.google.com/p/streamscraper/ to get track information from an icecast stream. I'm using it on android and so far it works as expected.

All you need is to setDataSource() and pass the URL as a String, then you must prepareAsync() and with a mp.setOnPreparedListener(this); or etc. you will get noticed when the MediaPlayer is done buffering, then all you need to do is mp.start(); P.S.: Don't forget to mp.stop, mp.reset and mp.release upon destroying the application. ;) I'm still thinking of a way to read the ICY info... I must either make my own buffering mechanism and write a buffer file (init the MediaPlayer with FileDescriptor) or make a separate connection from time to time to check for ICY info tags and close the connection... Any better ideas anyone?

Related

Can I use socket() on frameworks/native/service on Android?

I want to implement socket function in the Android frameworks/native/service/surfaceFlinger for sending screen information.
So, I made my source code about networking by using socket(), and inserted into the Android framework source tree.
However, it couldn't create socket descriptor.
It always returned -1 and errno is 13
So I added permission code like this:
// framework/frameworks/native/services/surfaceflinger/mynetwork.cpp
if (PermissionCache::checkCallingPermission("android.permission.INTERNET") < 0)
...
fd = socket(AF_INET, SOCK_DGRAM, 0);
But still doesn't work.
Any body know about this issue?
and know soution?
Thank you.

java.net.ProtocolException: unexpected end of stream

I am facing a strange issue, and I am not able to debug it out. I have implemented a logic for uploading stream of data and am using Volley for the same, I have customized a logic little bit in HurlStack, addBodyIfExists api,so that body of type "application/octet-stream" can be handled.
My logic is to post progress to user, so that UI can be updated indicating user progress in upload, below my logic for same.
int toRead = length; // File length
byte[] data = new byte[4096];
connection.setDoOutput(true);
if(length != -1) {
connection.setFixedLengthStreamingMode(length);
} else {
connection.setChunkedStreamingMode(4096);
}
OutputStream os;
int i;
int count;
os = connection.getOutputStream();
int progress= 0;
try {
for(i = 0; (count= is.read(data)) > 0; ++i) { // is, is not null and contains a valid input stream
os.write(data, 0, count); // at this line am getting unexpected end of stream
progress+= count;
if(i % 20 == 0) {
rs.deliverProgress(progress, 0L);
progress= 0;
}
}
os.flush();
} finally {
if(is != null) {
is.close();
}
if(os != null) {
os.close();
}
}
on executing above code am getting this, although I have verified, output stream is not null, neither do input stream, it fails in first iteration of read loop itself, am seeing it has read 4096 bytes and then trying to write the same.
java.net.ProtocolException: unexpected end of stream
at com.android.okhttp.internal.http.HttpConnection$FixedLengthSink.close(HttpConnection.java:326)
at com.android.okio.RealBufferedSink.close(RealBufferedSink.java:174)
at com.android.okio.RealBufferedSink$1.close(RealBufferedSink.java:142)
any help in debugging above will he highly appreciated.
This may help you :
That exception is thrown by FixedLengthInputStream when the expected number of bytes (usually set in the content-length header of the response) is larger than the actual data in the response.
Check that the content-length header is correct. (If you're supplying your own value for the content length, make sure it is correct.)
It would help to see your code that sets up the input stream.
Already Fixed it, please add "Accept-Encoding", "identity" in header, then the server-side will get command that it will not modify the response, then send back to Clients.
If you have checked everywhere in your code and tried every solution in stackoverflow and github but the issue still occurs, and you have only tested your code on emulator, then, you should try to run your code on your real device instead. Maybe it will work, or maybe it won't, but if you feel desperate, just have a try, seriously. I was astonished when I happened to find that my code ran with bugs on emulator everytime but successfully on my mobile phone. Besides, the code also ran sucessfully on others' android emulators. So I guess there is something wrong in my android studio configuration that I can't find out. I have no idea why this happen, just like we don't know why "Clean Project/Invalidate caches" sometimes works better than any solution.
It is a little strange that your data length might be unknown.
Is it a media file? Or a live stream?
Anyway, I tried to upload my live stream data. And it happened in the same error.
I added this setting to the Connection and solved my problem.
Transfer-Encoding : chunked
("setChunkedStreamingMode" didn't work. I still don't know why.)
This happens for me on android emulator and doesn't happen on my physical android device.
I was doing GET request to flask server running on 0.0.0.0 on my laptop from the android app.
To fix it on the emulator, add the servers ip address in the emulators proxy.
see How to set up Android emulator proxy settings
The exact problem i had was unexpected end of stream retrofit

Uploadprogress in Ionic

I have a form in which user can add information and add images. The images are base64 encoded so everything is stored in a json object. This object is sent to the server (with $resource) when the user submits it.
If a user adds for example 3 Images with about 2MB per Image, has a shitty connection like Edge, and wants to upload it it seems like it's taking forever. The user just sees the $ionicLoading overlay without information how long it will take or how much % are already uploaded.
The UX is bad because the user could assume, that the app froze or is in an endless loop and that it's just a bad app.
I have the following ideas but no idea if they are possible or
Is there a way in angular, cordova or ionic to get the browserinformation how much % are already uploaded?
Is there a way to get the current uploadspeed? I could get the size of my object by getting the length of my stringified JSON Object, divide it 1024 to get the kB. Then i would check the current uploadSpeed every second and add the current uploadspeed to a variable. With this information i could calculate the uploaded % approximately
JQuery ajaxForm Plugin?
Sounds like what you are looking for is progress events from XHR2.
Assuming your server is setup to handle XHR2 and return content-length, In plain JavaScript:
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
// Listen to the upload progress.
var progressBar = document.querySelector('progress');
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
progressBar.value = (e.loaded / e.total) * 100;
progressBar.textContent = progressBar.value; // Fallback for unsupported browsers.
}
};
xhr.send(blobOrFile);
}
upload(new Blob(['hello world'], {type: 'text/plain'}));
Upload speed is also calculable using the information returned in the progress event, as you described.
As for this implementation in AngularJS/Ionic, it seems like this is a longstanding issue within the framework that $http doesn't really support progress events.
I have seen implementations that utilize a special angular directive written for this, or even utilize a jQuery file upload implementation.

Android URLConnection class cannot get content lenght using 3G internet connection

I've got the following piece of code:
URL url = new URL("http://myserver.com/getFile.php");
URLConnection conexion = url.openConnection();
conexion.connect();
int lenghtOfFile = conexion.getContentLength();
Everything works fine until I work with WiFi connection. If I try to run this code when there is only GPRS/3G connection available, conexion.getContentLength() returns -1.
Any idea why?
EDIT:
I've check the headers using getHeaderFields(). They are different if I use 3G network. Basically there is no Content-Length in this case. Any idea why server returns different headers? I'm not using any special script to provide the file, I only get the file that is placed at given location.
Entire header for the WiFi case:
{Accept-Ranges=[bytes], Connection=[Keep-Alive], Content-Length=[628254], Content-Type=[text/plain; charset=UTF-8], Date=[Tue, 29 Nov 2011 11:22:50 GMT], ETag=["7a0c7-9961e-4af3f38778500"], Keep-Alive=[timeout=15], Last-Modified=[Fri, 14 Oct 2011 09:52:52 GMT], Server=[Apache/2.2.9 (Debian) PHP/5.2.6-1+lenny9 with Suhosin-Patch mod_python/3.3.1 Python/2.6.6 mod_ssl/2.2.9 OpenSSL/0.9.8o mod_wsgi/3.3 mod_perl/2.0.4 Perl/v5.10.0]}
Entire header for the case when using 3G:
{Accept-Ranges=[bytes], Connection=[Keep-Alive], Content-Type=[text/plain; charset=UTF-8], Date=[Tue, 29 Nov 2011 11:20:33 GMT], ETag=["7a0c7-9961e-4af3f38778500"], Keep-Alive=[timeout=15], Last-Modified=[Fri, 14 Oct 2011 09:52:52 GMT], Server=[Apache/2.2.9 (Debian) PHP/5.2.6-1+lenny9 with Suhosin-Patch mod_python/3.3.1 Python/2.6.6 mod_ssl/2.2.9 OpenSSL/0.9.8o mod_wsgi/3.3 mod_perl/2.0.4 Perl/v5.10.0], Transfer-Encoding=[chunked], Warning=[214 warkaz-fe07 "Transformation applied"]}
Are you sure that the server provides the content length by sending the Content-Length header in the response?
From the headers it's clear that your provider has some kind of proxy in place that does a transformation, stripping the content-length in the process. The warning header clearly indicates this. You could try returning a different type of content type (you are now getting text/plain), maybe this particular proxy won't touch it. It's not a great solution of course, there are a lot things carriers may have to "optimize" their network in some way.
You could also try a HEAD request using a range header to get a ballpark of the content size. In that case you'd guess a few ranges, like 100k, 1000k etc to see if the server thinks that's an acceptable range. You could use that fake range for your progress. Again, this isn't a very good solution but if you really need the progress, it's something to try.
In the end it's best to just show the progress as unknown if there's no length known.
Since you are using
new URL("http://myserver.com/getFile.php");
I suppose you are using a personal server that you have set up, and when using WiFi your phone is in your local network and thereby can see your server, but when you are trying to connect via GPRs/3G you are trying to access your local server from the internet.
It is probably due to a limitation from your carrier. Try to avoid needing this value. (for example, by reading the inputStream until you cannot read it).

Jsoup and gzipped html content (Android)

I've been trying all day to make this thing works but it's still not right yet. I've checked so many posts around here and tested so many different implementations that I'dont know where to look now...
Here is my situation, I have a small php test file (gz.php) on my server wich looks like this :
header("Content-Encoding: gzip");
print("\x1f\x8b\x08\x00\x00\x00\x00\x00");
$contents = gzcompress("Is it working?", 9);
print($contents);
This is the simplest I could do and it works fine with any web browser.
Now I have an Android activity using Jsoup that has this code :
URL url = new URL("http://myServerAdress.com/gz.php");
doc = Jsoup.parse(url, 1000);
Which cause an empty EOFException on the "Jsoup.parse" line.
I've read everywhere that Jsoup is supposed to parse gzipped content without having to do anything special, but obviously, there's something missing.
I've tried many other ways like using Jsoup.connect().get() or InpuStream, GZipInputStream and DataInpuStream. I did try the gzDeflate() and gzencode() methods from PHP as well but no luck either. I even tried not to declare the header-encoding in PHP and try to deflate the content later...but it was as clever as effective...
It has to be something "stupid" I'm missing but I just can't tell what... anybody has an idea?
(ps : I'm using Jsoup 1.7.0, so the latest one as of now)
The asker indicated in a comment that gzcompress was writing a CRC that was both incorrect and incomplete, according to information from here, the operative code being:
// Display the header of the gzip file
// Thanks ck#medienkombinat.de!
// Only display this once
echo "\x1f\x8b\x08\x00\x00\x00\x00\x00";
// Figure out the size and CRC of the original for later
$Size = strlen($contents);
$Crc = crc32($contents);
// Compress the data
$contents = gzcompress($contents, 9);
// We can't just output it here, since the CRC is messed up.
// If I try to "echo $contents" at this point, the compressed
// data is sent, but not completely. There are four bytes at
// the end that are a CRC. Three are sent. The last one is
// left in limbo. Also, if we "echo $contents", then the next
// byte we echo will not be sent to the client. I am not sure
// if this is a bug in 4.0.2 or not, but the best way to avoid
// this is to put the correct CRC at the end of the compressed
// data. (The one generated by gzcompress looks WAY wrong.)
// This will stop Opera from crashing, gunzip will work, and
// other browsers won't keep loading indefinately.
//
// Strip off the old CRC (it's there, but it won't be displayed
// all the way -- very odd)
$contents = substr($contents, 0, strlen($contents) - 4);
// Show only the compressed data
echo $contents;
// Output the CRC, then the size of the original
gzip_PrintFourChars($Crc);
gzip_PrintFourChars($Size);
Jonathan Hedley commented, "jsoup just uses a normal Java GZIPInputStream to parse the gzip, so you'd hit that issue with any Java program." The EOFException is presumably due to the incomplete CRC.

Categories

Resources