public void downdown(View view) {
try {
URL url = new URL("http://myserver.com:7005/media/databases/myfile.db");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
urlConnection.connect();
File SDCardRoot = Environment.getExternalStorageDirectory();
File file = new File(SDCardRoot,"myfile.db");
FileOutputStream fileOutput = new FileOutputStream(file);
InputStream inputStream = urlConnection.getInputStream();
int totalSize = urlConnection.getContentLength();
int downloadedSize = 0;
byte[] buffer = new byte[1024];
int bufferLength = 0;
while ( (bufferLength = inputStream.read(buffer)) > 0 ) {
fileOutput.write(buffer, 0, bufferLength);
downloadedSize += bufferLength;
//actualizaProgreso(downloadedSize, totalSize);
}
fileOutput.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
And manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.downloader"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Error:
When i press the button download (this button calls downdown function: this function downloads a file from a server) i get the following error:
java.lang.IllegalStateException: Could not execute method of the activity
public void downdown(View view) {
new Thread() {
public void run() {
downdown();
}
}.start();
}
public void downdown(){
try {
URL url = new URL("http://myserver.com:7005/media/databases/myfile.db");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
urlConnection.connect();
File SDCardRoot = Environment.getExternalStorageDirectory();
File file = new File(SDCardRoot,"myfile.db");
FileOutputStream fileOutput = new FileOutputStream(file);
InputStream inputStream = urlConnection.getInputStream();
int totalSize = urlConnection.getContentLength();
int downloadedSize = 0;
byte[] buffer = new byte[1024];
int bufferLength = 0;
while ( (bufferLength = inputStream.read(buffer)) > 0 ) {
fileOutput.write(buffer, 0, bufferLength);
downloadedSize += bufferLength;
//actualizaProgreso(downloadedSize, totalSize);
}
fileOutput.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
You cannot have network actions within the main thread.
Look into AsyncTask and multi-Threading.
http://developer.android.com/reference/android/os/AsyncTask.html
Android : Loading an image from the Web with Asynctask
If you really want to improve you skills I suggest not using an instance of thread to start your process. I suggest using ExecutorService
Here is a guide to how to use http://tutorials.jenkov.com/java-util-concurrent/scheduledexecutorservice.html
Related
I am sending images to firebase. but when my upload pictures method starts running, I get no auth token printed into my logcat couple of times. I tried using both camera and gallery, but they both make the same output even though my firebase storage rules are:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}
}
}
And my code is:
if (fragment3.isAdded()) {
EditText plantdetails = (EditText) fragment3.getView().findViewById(R.id.plantdetails);
if (plantdetails.getText().toString().equals("")) {
Toast.makeText(newPlant.this, "I think you forgot something.", Toast.LENGTH_LONG).show();
} else {
plants plantss = new plants();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(newPlant.this);
prefs.edit().putString("pldetails", plantdetails.getText().toString()).apply();
String pname = prefs.getString("plname","null");
String pdate = prefs.getString("pldate","null");
String petails = prefs.getString("pldetails","null");
plantss.setPlname(pname);
plantss.setPldate(pdate);
plantss.setPldetails(petails);
reference.child("Plants").child(pname).setValue(plantss);
try {
Fileuploader();
}catch (FileNotFoundException e){
e.printStackTrace();
}
}
}
if (fragment4.isAdded()){
}
}
});
}
private void Fileuploader() throws FileNotFoundException {
String imageid;
progress.showProgress(newPlant.this,"Loading...",false);
DatabaseHelper databaseHelper = new DatabaseHelper(newPlant.this);
Cursor getimage = databaseHelper.GetPath();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(newPlant.this);
String plname = prefs.getString("plname","null");
int count = 0;
int count2 = 0;
if (getimage !=null){
while (getimage.moveToNext()) {
System.out.println("IMAGE IS THIS MY MAN: "+ getimage.getString(0));
Bitmap bm = BitmapFactory.decodeFile(getimage.getString(0));
if (bm == null){
return;
}else {
ByteArrayOutputStream out = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 35, out);
imageid = System.currentTimeMillis() + "_" + (count++) + "." + getExtension(uri);
DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Plants").child(plname).child("PlantImages");
String imagekey = reference.push().getKey();
reference.child(imagekey).child("ImageID").setValue(imageid);
reference.child(imagekey).child("ID").setValue(count2++);
System.out.println("IMAGES UPLOADEDDDD: " + imageid);
byte[] data = out.toByteArray();
StorageReference Ref = mStorageRef.child(imageid);
Ref.putBytes(data)
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
// Get a URL to the uploaded content
//Uri downloadUrl = taskSnapshot.getDownloadUrl();
//Toast.makeText(profuctadd.this,"Image uploaded",Toast.LENGTH_LONG).show();
progress.hideProgress();
Intent intent = new Intent(newPlant.this, Donenewplant.class);
startActivity(intent);
finish();
DatabaseHelper mDatabaseHelper = new DatabaseHelper(newPlant.this);
Cursor cursor2 = mDatabaseHelper.DeleteDataOfTableImagesAr();
cursor2.moveToNext();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle unsuccessful uploads
// ...
Toast.makeText(newPlant.this, "Failed", Toast.LENGTH_LONG).show();
System.out.println("FAILED:::: "+exception);
}
});
}
}
}
}
Mainfest file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.varroxsystems.plant">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="#drawable/plant"
android:label="#string/app_name"
android:roundIcon="#drawable/plant"
android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
android:theme="#style/AppTheme">
<activity android:name=".Donenewplant"></activity>
<activity android:name=".newPlant" />
<activity android:name=".MainActivity" />
<activity android:name=".Splash_screen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.varroxsystems.plant.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
</application>
</manifest>
So does anyone know a solution for that, or is it just a bug, because I use the same exact code in another app and it works just fine.
EDIT: The other app I use uses a different database, not the same one.
I am trying to make possible for users to update ann app from device. We have a server where from user can download apk file with new version of an app.
Here is the code which starts after button pressed:
Handler handler = new Handler(Looper.getMainLooper());
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
File folder = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString());
File file = new File(folder.getAbsolutePath(), "localdb.apk");
final Uri uri = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) ?
FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", file) :
Uri.fromFile(file);
if (file.exists())
file.delete();
//url to get app from server
String url = Names.UPDATE_URL;
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL sUrl = new URL(url);
connection = (HttpURLConnection) sUrl.openConnection();
connection.connect();
// download the file
input = connection.getInputStream();
output = new FileOutputStream(file);
byte data[] = new byte[4096];
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
output.write(data, 0, count);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
handler.post(new Runnable() {
#Override
public void run() {
Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE)
.setData(uri)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(install);
}
});
}
});
thread.start();
Here is what i have in manifest:
...<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.QUICKBOOT_POWERON" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="ru.mob.myapp.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
...
and finally an xml file provider_paths:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>
So, everything works fine, I download apk with new version, it is named same as already installed,
system asks me to install (update) my application, but when everything is almoust done I get "App is not installed" message without any details.
Does anyone have a solution, hint, adviсe?
i am trying to build an application that downloads files (e.g. ".jpg", ".txt") from the web when given a url. its not really meant to be a real world application, more just an exercise to help me become more comfortable with network and io based code. for now i am just pulling the bytes from the url and then converting them to a string and logging that. then from there i want to write this to a file. the problem i am running into now is that im getting a file not found exception stating that access is denied:
07-11 21:03:14.458 19072-20051/com.example.zacharymcdaniel.webdownloader E/AsyncDownload: network errorjava.io.FileNotFoundException: /sdcard/-1157023572 (Permission denied)
java.io.FileNotFoundException: /sdcard/-1157023572 (Permission denied)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:221)
at java.io.FileOutputStream.<init>(FileOutputStream.java:169)
at com.example.zacharymcdaniel.webdownloader.AsyncDownload.doInBackground(AsyncDownload.java:60)
at com.example.zacharymcdaniel.webdownloader.AsyncDownload.doInBackground(AsyncDownload.java:23)
at android.os.AsyncTask$2.call(AsyncTask.java:304)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
here is my manifest:
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
and the code for the asynctask implementation i am using to perform the download and write operation:
public class AsyncDownload extends AsyncTask<Void, Void, Void>{
private static final String TAG = "AsyncDownload";
private static final String STORAGE_LOCATION = "/sdcard/"; //android directory picker is needed
private URL url;
private ArrayList<Byte> bytes = new ArrayList<>();
public AsyncDownload(URL url){
this.url = url;
}
#Override
protected Void doInBackground(Void... params){
try{
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int c;
while ((c = in.read()) != -1){
buffer.write(c);
}
Log.i(TAG, buffer.toString());
Random rand = new Random(4L);
String temp = String.valueOf(rand.nextInt());
String finalLocation = STORAGE_LOCATION + temp;
File file = new File(finalLocation);
file.getParentFile().mkdirs();
file.setWritable(true);
file.setReadable(true);
FileOutputStream fOut = new FileOutputStream(file);
fOut.write(buffer.toByteArray());
fOut.flush();
fOut.close();
FileInputStream fIn = new FileInputStream(finalLocation);
String reRead = new String();
int a;
while ((a = fIn.read()) != -1){
reRead += a;
}
Log.i(TAG, reRead);
//this section is for automatic file naming
/*Random rand = new Random(5L);
String fileNumber = String.valueOf(rand.nextInt());
StringBuilder sb = new StringBuilder();
sb.append(fileNumber).append("download"); //definitely needs work
Log.i(TAG, sb.toString());*/
//FileOutputStream fOut = new FileOutputStream()
}catch (IOException ioe){
Log.e(TAG, "network error" + ioe.toString(), ioe);
}
return null;
}
}
i am pretty new to this so i may have made some pretty obvious mistakes. please help solve this error. thank you.
add this to your activity
if (ContextCompat.checkSelfPermission(context,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(InterviewListActivity.this,
new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_EXT_STORAGE);
}
call this method in your activity
protected void checkPermissions() {
final int writeExternalPermissionCheck = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (writeExternalPermissionCheck != PackageManager.PERMISSION_GRANTED {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
Constant.REQUEST_CODE_ASK_PERMISSIONS);
}
}
}
and override this method
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case Constant.REQUEST_CODE_ASK_PERMISSIONS:
if (grantResults!=null) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Call ur save method here or change the variable value true
} else {
Logger.toast(this, "Please enable write permission from Apps);
}
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
Hope This helps.
Api level 6.0 or above you need runtime permission
I'm trying to make a mini yamba.newcircle.com from my Android project training. I'm saving text messages when the Internet is not available, and with connectivity broadcast receiver if the Internet is up. This app automatically starts a service that loops to push all saved text rows in ActiveAndroid from a table, via HTTP posts to the web API.
When I turn Wifi off, save some messages with ActiveAndroid, and turn Wifi back on; if my app connects, it simply crashes with NullPointereException.
Any suggestions?
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="pt.flag.miniyamba" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name="MiniYamba"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme" >
<meta-data
android:name="AA_DB_NAME"
android:value="yamba.db" />
<meta-data
android:name="AA_DB_VERSION"
android:value="5" />
<activity android:name=".Main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".OnlineStatus" >
</activity>
<activity android:name=".OfflineStatus" >
</activity>
<activity android:name=".SingleStatus" >
</activity>
<activity android:name=".NewStatus" >
</activity>
<receiver android:name=".NetworkBroadCastReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"></action>
</intent-filter>
</receiver>
<service android:name=".PushOfflineSavedService"/>
</application>
</manifest>
broacast
public class NetworkBroadCastReceiver extends BroadcastReceiver {
private Context mContext;
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager manager =(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = manager.getActiveNetworkInfo();
if(netInfo != null && netInfo.isConnectedOrConnecting()){
Toast.makeText(context, "net is up, pushing our previous offline saved posts ", Toast.LENGTH_SHORT).show();
//inicializar o servico de push de posts, guardados anteriormente
Intent novointent = new Intent(context, PushOfflineSavedService.class);
context.startService(novointent);
}
//mudou de conectividade, mas nao tem internet
else{
Toast.makeText(context, "Connectivity is changed. Internet seens not working.", Toast.LENGTH_SHORT).show();
}
}
}
intentservice
public class PushOfflineSavedService extends IntentService {
private String LOG_TAG;
public PushOfflineSavedService() {
super("PushOfflineSavedService");
ActiveAndroid.initialize(this);
}
#Override
protected void onHandleIntent(Intent intent) {
//enviar os status guardados, por enviar
List<OfflinePostToSend> lista = new Select().from(OfflinePostToSend.class).execute();
//loop para enviar os status
if (lista.size() > 0) {
for (int i = 0; i < lista.size(); i++) {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
try {
String path = "http://yamba.newcircle.com/api/statuses/update.json";
String status = lista.get(i).getText();
URL url = new URL(path);
String userPass = "student:password";
String token = "Basic " + Base64.encodeToString(userPass.getBytes(), Base64.NO_WRAP);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("POST");
// Adicionar o token como header do pedido
urlConnection.addRequestProperty("Authorization", token);
urlConnection.setDoOutput(true);
String postParameters = "status="+status;
urlConnection.setFixedLengthStreamingMode(postParameters.getBytes().length);
urlConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
// Adicionar o status ao método post
PrintWriter out = new PrintWriter(urlConnection.getOutputStream());
out.print(postParameters);
out.close();
reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(urlConnection.getInputStream())));
StringBuilder buffer = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
buffer.append("\n");
}
//se buffer nao for full, temos 1 respota do API
if (buffer.length() != 0) {
// Stream was NOT empty.
//apagar este elemento da lista e da db
lista.get(i).delete();
}
//return buffer.toString();
} catch (IOException e) {
Log.e(LOG_TAG, "Error ", e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e(LOG_TAG, "Error closing stream", e);
}
}
}
}
}
}
}
The ActiveAndroid guide shows the call to initialize() in an Application subclass, like this:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
ActiveAndroid.initialize(this);
}
}
Try extending Application and putting your initialize() call there instead of in the service.
I have an android activity, which connects to a java class and sends data packets to it in form of sockets. The class receives the sound packets and throws them to PC speakers. The code is working excellently, but there is a constant jitter/ interruption while the sound is played in PC speakers.
The android activity:
public class SendActivity extends Activity {
private Button startButton, stopButton;
public byte[] buffer;
public static DatagramSocket socket;
private int port = 50005;
AudioRecord recorder;
private int sampleRate = 8000;
#SuppressWarnings("deprecation")
private int channelConfig = AudioFormat.CHANNEL_IN_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig,
audioFormat);
private boolean status = true;
int bufferSizeInBytes;
int bufferSizeInShorts;
int shortsRead;
short audioBuffer[];
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_send);
startButton = (Button) findViewById(R.id.start_button);
stopButton = (Button) findViewById(R.id.stop_button);
startButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
status = true;
startStreaming();
}
});
stopButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
status = false;
recorder.release();
Log.d("VS", "Recorder released");
}
});
minBufSize += 5120;
System.out.println("minBufSize: " + minBufSize);
}
public void startStreaming() {
Thread streamThread = new Thread(new Runnable() {
#Override
public void run() {
try {
DatagramSocket socket = new DatagramSocket();
Log.d("VS", "Socket Created");
byte[] buffer = new byte[minBufSize];
Log.d("VS", "Buffer created of size " + minBufSize);
DatagramPacket packet;
//machine's IP
final InetAddress destination = InetAddress
.getByName("192.168.1.20");
Log.d("VS", "Address retrieved");
recorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_RECOGNITION,
sampleRate, channelConfig, audioFormat,
minBufSize * 10);
Log.d("VS", "Recorder initialized");
recorder.startRecording();
while (status == true) {
// reading data from MIC into buffer
minBufSize = recorder.read(buffer, 0, buffer.length);
// putting buffer in the packet
packet = new DatagramPacket(buffer, buffer.length,
destination, port);
socket.send(packet);
System.out.println("MinBufferSize: " + minBufSize);
}
} catch (UnknownHostException e) {
Log.e("VS", "UnknownHostException");
} catch (IOException e) {
e.printStackTrace();
Log.e("VS", "IOException");
}
}
});
streamThread.start();
}
}
The android layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".SendActivity" >
<Button
android:id="#+id/stop_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/start_button"
android:layout_alignBottom="#+id/start_button"
android:layout_toRightOf="#+id/start_button"
android:text="Stop" />
<Button
android:id="#+id/start_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="79dp"
android:layout_marginTop="163dp"
android:text="Start" />
</RelativeLayout>
Android Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.audiostreamsample"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
</uses-permission>
<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.audiostreamsample.SendActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
The class to receive the data packets and throw them to the PC speakers:
class Server {
AudioInputStream audioInputStream;
static AudioInputStream ais;
static AudioFormat format;
static boolean status = true;
static int port = 50005;
static int sampleRate = 8000;
public static void main(String args[]) throws Exception {
DatagramSocket serverSocket = new DatagramSocket(50005);
/**
* Formula for lag = (byte_size/sample_rate)*2
* Byte size 9728 will produce ~ 0.45 seconds of lag. Voice slightly broken.
* Byte size 1400 will produce ~ 0.06 seconds of lag. Voice extremely broken.
* Byte size 4000 will produce ~ 0.18 seconds of lag. Voice slightly more broken then 9728.
*/
byte[] receiveData = new byte[5000];
format = new AudioFormat(sampleRate, 16, 1, true, false);
while (status == true) {
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
serverSocket.receive(receivePacket);
ByteArrayInputStream baiss = new ByteArrayInputStream(
receivePacket.getData());
ais = new AudioInputStream(baiss, format, receivePacket.getLength());
toSpeaker(receivePacket.getData());
}
}
public static void toSpeaker(byte soundbytes[]) {
try {
DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, format);
SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
sourceDataLine.open(format);
FloatControl volumeControl = (FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN);
volumeControl.setValue(6.0206f);
sourceDataLine.start();
sourceDataLine.open(format);
sourceDataLine.start();
System.out.println("format? :" + sourceDataLine.getFormat());
sourceDataLine.write(soundbytes, 0, soundbytes.length);
System.out.println(soundbytes.toString());
sourceDataLine.drain();
sourceDataLine.close();
} catch (Exception e) {
System.out.println("Not working in speakers...");
e.printStackTrace();
}
}
}
If you want to test the app in your IDE, then simply create two different projects, one for the android app and one for the server class.
In the android app just add the IP of your machine and run the app on a device, the mobile and the computer should belong to the same network. Please execute the server class as a java application.
The jitter will be prominent and irritating but the voices will be more or less clear. Please suggest me what to do to get a clearer output.
You need to have some coded support for actual streaming.
There's a little more to consider than just sending datagrams and hoping for the best.
Real networks are not perfect.
Delay: packets take time
Jitter : the time a packet takes in flight is not constant
Dropped packets: sometimes they don't make it.
Reordering : sometimes packets arrive in a different order to the sending.
You should read up on simple media streaming protocols like RTP and perhaps use a library that provides RTP to both ends. RTP commonly sits atop UDP.
TCP streaming for audio can be less helpful than UDP/RTP , as you'd have to turn off Nagling.
You will at a minimum need a small buffer at the receiver end to prevent buffer empty causing sound dropouts.