I want to write audio data that comes from the microphone to a file.
I have 2 threads: one "listen" for the audio data and send it to the second thread(the consumer) which stores it in a queue. The consumer thread constantly polls the queue and writes on the file the audioData as byte[].
I use RandomAccessFile for the writing. Considering that everything is syncronized in my code, should I use some non-thread-safe class like FileChannel?
below is some code snippets:
Read audio data
private void read(){
// fill the buffer with the mic input
readFully(buffer, 0, buffer.length);
// creates audioData from this buffer
WAVData audioData = new WAVData(buffer.length);
audioData.arrayCopy(buffer);
// add it to the consumer
mAudioWritter.add(audioData);
}
Write audio data - the consumer clas
public void add(WAVEntity audioEntity){
mQueue.add(audioEntity);
synchronized (mLock) {
mLock.notify();
}
}
#Override
public void run() {
synchronized (mLock) {
while(!isFinalized){
//wait if queue is empty
while(mQueue.isEmpty()){
try {
mLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
WAVEntity entity = mQueue.poll();
if(entity != null){
try {
entity.writeOnFile(file);
} catch (AudioRecorderError e) {
// error handling
}
}
}
}
callback.threadFinished(this);
// try closing this file
try {
file.close();
} catch (IOException e) {
Log.e(getClass().getName(), e.getMessage(), e);
}
}
#Override
public boolean writeOnFile(RandomAccessFile fWriter) throws AudioRecorderError {
synchronized (data) {
//write on the file
try {
fWriter.write(data);
} catch (Exception e) {
AudioRecorderError error = new AudioRecorderError(e, "Data chunck was not written. See stack trace.");
throw error;
}
}
return false;
}
Related
I am trying to write Short[] to wav audio file using file output stream but the file only contains scratch sound.
The reason i am using short[] rather than byte[] is because i am trying to use an external library which provides Voice Activity Detection . I did add wav header provided in Android Audio Record to wav and i tried to convert Short[] to byte[] using Converting Short array from Audio Record to Byte array without degrading audio quality? but none of the above links were able to help me.
Here is my code:
private class ProcessVoice implements Runnable {
#Override
public void run() {
File fl = new File(filePath, AUDIO_RECORDING_FILE_NAME);
try {
os = new BufferedOutputStream(new FileOutputStream(fl));
} catch (FileNotFoundException e) {
Log.w(TAG, "File not found for recording ");
}
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
while (!Thread.interrupted() && isListening && audioRecord != null) {
short[] buffer = new short[vad.getConfig().getFrameSize().getValue() * getNumberOfChannels() * 2];
audioRecord.read(buffer, 0, buffer.length);
isSpeechDetected(buffer);
}
}
private void isSpeechDetected(final short[] buffer) {
vad.isContinuousSpeech(buffer, new VadListener() {
#Override
public void onSpeechDetected() {
callback.onSpeechDetected();
bytes2 = new byte[buffer.length * 2];
ByteBuffer.wrap(bytes2).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(buffer);
//Log.w(TAG, String.valueOf(buffer));
try {
// // writes the data to file from buffer
// // stores the voice buffer
os.write(header, 0, 44);
working = true;
os.write(bytes2, 0, bytes2.length);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onNoiseDetected() {
callback.onNoiseDetected();
if(working == true){
working = false;
try {
doneRec();
} catch (IOException e) {
e.printStackTrace();
}
}
//Log.w(TAG, String.valueOf(bytes2));
}
});
}
}
I want to make a dubbing app in Android.
Flow of the app is:
Get video and audio from the gallery.
Reduce the original sound of Video file. And mix (Dub) the selected audio on this video file.
After mixing the audio on this video file save it in to external memory.
I am using MediaMuxer for this, but m not success. Please help me regarding this.
Regards,
Prateek
even i was looking for the same to dub my video with an audio using mediaMuxer, MediaMuxer was a little difficult concept for me to understand as i am beginner . i ended up refering this github code. https://github.com/tqnst/MP4ParserMergeAudioVideo
it was my saviour. really thanx to that person.
i just picked up the code i wanted from it, i.e dubbing a video with the audio i specify.
here is my code i used in my project below
private void mergeAudioVideo(String originalVideoPath,String AudioPath,String OutPutVideoPath) {
// TODO Auto-generated method stub
Movie video = null;
try {
new MovieCreator();
video = MovieCreator.build(originalVideoPath);
} catch (RuntimeException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Movie audio = null;
try {
new MovieCreator();
audio = MovieCreator.build(AudioPath);
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
List<Track> videoTracks = new LinkedList<Track>();
for (Track t : video.getTracks()) {
if (t.getHandler().equals("vide")) {
videoTracks.add(t);
//seperate the video from the orginal video
}
}
Track audioTrack = audio.getTracks().get(0);// get your audio track to dub the video
Movie result = new Movie();
result.addTrack(videoTracks.get(0)); // add the video seprated from the originals
result.addTrack(audioTrack); //add the track to be put in resul video
Container out = new DefaultMp4Builder().build(result);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(OutPutVideoPath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
BufferedWritableFileByteChannel byteBufferByteChannel = new BufferedWritableFileByteChannel(fos);
try {
out.writeContainer(byteBufferByteChannel);
byteBufferByteChannel.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
and here is the BufferedWritableFileByteChannel class to write the outputVideo data to the directory.
public class BufferedWritableFileByteChannel implements WritableByteChannel {
private static final int BUFFER_CAPACITY = 1000000;
private boolean isOpen = true;
private final OutputStream outputStream;
private final ByteBuffer byteBuffer;
private final byte[] rawBuffer = new byte[BUFFER_CAPACITY];
public BufferedWritableFileByteChannel(OutputStream outputStream) {
this.outputStream = outputStream;
this.byteBuffer = ByteBuffer.wrap(rawBuffer);
}
#Override
public int write(ByteBuffer inputBuffer) throws IOException {
int inputBytes = inputBuffer.remaining();
if (inputBytes > byteBuffer.remaining()) {
dumpToFile();
byteBuffer.clear();
if (inputBytes > byteBuffer.remaining()) {
throw new BufferOverflowException();
}
}
byteBuffer.put(inputBuffer);
return inputBytes;
}
#Override
public boolean isOpen() {
return isOpen;
}
#Override
public void close() throws IOException {
dumpToFile();
isOpen = false;
}
private void dumpToFile() {
try {
outputStream.write(rawBuffer, 0, byteBuffer.position());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
and dont forget to add the libraries in your project.
this may not be the exact answer to your question. but atleast it will able to shed some light on the probable solution.
I am pogramming a bluetooth device. I found when I tried to disconnect, the app will hang for some devices.
public class ConnectionThread extends Thread {
....
#Override
public void run() {
bReading = true;
while (bReading) {
try {
if (mInStream==null) break;
bytes = mInStream.read(buffer);
} catch (IOException e) {
cancel();
break;
}
}
}
public void cancel() {
bReading = false;
if (mInStream != null) {
try {
mInStream.close();
} catch (Exception e) {
e.printStackTrace();
}
mInStream = null;
}
So I call the cancel function to stop the while loop.
For above logic, there will be "thread dead" event, which is not good. For some device, the "thead dead" event will even cause the app hangs.
However, I dont know what wrong is the above code. I am not sure if it is caused any synchronous issue? How to improve the flow to remove the potential hang issue. any kind of advice is highly appreciated. Thanks.
To stop the communication you can close the socket :
"
while (true) {
try {
if (mInStream==null) break;
bytes = mInStream.read(buffer);
} catch (IOException e) {
break;
}
}
"
public void cancel(){
try{
mmSocket.close();
if(DEBUG_MODE){
Log.i(TAG, "socket closed");
}
}catch(IOException e){
Log.e(TAG, "socket close failed", e);
}
}
When the socket close the loop will naturally break, since the read will fail
I'm writing a library project for multiple APPs to use. And for some reason, I must make a function mutual exclusion for different APPs, so I need a cross-process lock. But as far as I know, in android APPs can only write to it's own file's directory in internal storage, and external storage is unreliable because some device don't have one. So file lock seems not applicable for me, so is there any other way to implement cross-process lock?
thanks~
If you do not want to (or you can not) use flock or fcntl, maybe you can use LocalServerSocket to implement a spinlock.
For example:
public class SocketLock {
public SocketLock(String name) {
mName = name;
}
public final synchronized void tryLock() throws IOException {
if (mServer == null) {
mServer = new LocalServerSocket(mName);
} else {
throw new IllegalStateException("tryLock but has locked");
}
}
public final synchronized boolean timedLock(int ms) {
long expiredTime = System.currentTimeMillis() + ms;
while (true) {
if (System.currentTimeMillis() > expiredTime) {
return false;
}
try {
try {
tryLock();
return true;
} catch (IOException e) {
// ignore the exception
}
Thread.sleep(10, 0);
} catch (InterruptedException e) {
continue;
}
}
}
public final synchronized void lock() {
while (true) {
try {
try {
tryLock();
return;
} catch (IOException e) {
// ignore the exception
}
Thread.sleep(10, 0);
} catch (InterruptedException e) {
continue;
}
}
}
public final synchronized void release() {
if (mServer != null) {
try {
mServer.close();
} catch (IOException e) {
// ignore the exception
}
}
}
private final String mName;
private LocalServerSocket mServer;
}
I'm trying to develop an Android application which transfers images from one device to another. The received image would then be shown on the ImageView inside my application. To achieve my task, I thought to send a byte array of the bitmap. I'm able to get the first image on the imageview. But, as soon as I click on the button to send another image the application fails to send the bitmap. It shows me an exception "java.io.IOException: Service fiscovery failed." To send any image successfully I need to restart my application on the receiving/remote device. Can anyone please suggest a solution to mu problem. The logcat has also been included below.
Code to establish the connection:
private class StartConnectionThread extends Thread{
private final BluetoothSocket bluetoothSocket;
private final BluetoothDevice bluetoothDevice;
public StartConnectionThread(BluetoothDevice device){
BluetoothSocket tempBluetoothSocket=null;
bluetoothDevice=device;
try
{
System.out.println(uuid);
tempBluetoothSocket=device.createRfcommSocketToServiceRecord(uuid);
}
catch(IOException ioException)
{
}
bluetoothSocket=tempBluetoothSocket;
}
#Override
public void run() {
// TODO Auto-generated method stub
bluetoothAdapter.cancelDiscovery();
try
{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bluetoothSocket.connect();
}
catch(IOException ioException)
{
System.out.println("bluetoothSocketInThread failed");
try
{
bluetoothSocket.close();
}
catch(IOException cancelIOException)
{
}
return;
}
manageConnectedSocket(bluetoothSocket);
}
public void cancel()
{
try
{
bluetoothSocket.close();
}
catch(IOException ioException)
{
}
}
}
Code to accept the connection:
private class AcceptConnectionThread extends Thread
{
private final BluetoothServerSocket bluetoothServerSocket;
public AcceptConnectionThread() {
// TODO Auto-generated constructor stub
System.out.println("constructor");
BluetoothServerSocket tempBluetoothServerSocket=null;
try
{
tempBluetoothServerSocket=bluetoothAdapter.listenUsingRfcommWithServiceRecord("My Souvenirs", uuid);
}
catch(IOException ioException)
{
}
bluetoothServerSocket=tempBluetoothServerSocket;
}
#Override
public void run() {
// TODO Auto-generated method stub
BluetoothSocket bluetoothSocket=null;
while(true)
{
try
{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(bluetoothServerSocket);
if(bluetoothServerSocket!=null)
{
bluetoothSocket=bluetoothServerSocket.accept();
}
System.out.println("accept");
}
catch(IOException ioException){
break;
}
if(bluetoothSocket!=null)
{
manageConnectedSocket(bluetoothSocket);
try {
bluetoothServerSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
}
public void cancel()
{
try{
bluetoothServerSocket.close();
}
catch(IOException ioException){
}
}
}
Code to manage the connection:
private class ManageConnectedDevicesThread extends Thread
{
private final BluetoothSocket connectedBluetoothSocket;
public ManageConnectedDevicesThread(BluetoothSocket socket) {
// TODO Auto-generated constructor stub
connectedBluetoothSocket=socket;
InputStream tempInputStream=null;
OutputStream tempOutputStream=null;
try
{
tempInputStream=socket.getInputStream();
tempOutputStream=socket.getOutputStream();
}
catch(IOException ioException)
{
}
inputStream=tempInputStream;
outputStream=tempOutputStream;
}
#Override
public void run() {
// TODO Auto-generated method stub
byte[] buffer=new byte[1024*8];
int bytes;
while(true)
{
try
{
bytes=inputStream.read(buffer);
handler.obtainMessage(MESSAGE_READ,bytes,-1,buffer).sendToTarget();
System.out.println("handler");
}
catch(IOException ioException)
{
System.out.println("for handler:" +ioException);
break;
}
}
}
public void write(byte[] bytes)
{
try
{
outputStream.write(bytes);
}
catch(IOException ioException){
System.out.println("exception in wrie tatement of managing connections");
}
}
public void close()
{
try {
connectedBluetoothSocket.close();
} catch (IOException e) {
// TODO: handle exception
}
}
}
Code to reset the connection:
void resetConnection()
{
if(inputStream!=null)
{
try {
inputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(outputStream!=null)
{
try {
outputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(startConnectionThread!=null)
{
System.out.println("start wala active tha");
startConnectionThread.cancel();
}
if(acceptConnectionThread!=null)
{
System.out.println("accept wala active tha");
acceptConnectionThread.cancel();
}
if(manageConnectedDevicesThread!=null)
{
System.out.println("manage wala active tha");
manageConnectedDevicesThread.close();
}
}
}
code for handler is shown below:
private final Handler handler=new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_READ:
System.out.println("MESSAGE_READ");
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
byte[] b=readMessage.getBytes();
Bitmap bitmap1=BitmapFactory.decodeByteArray(readBuf, 0, readBuf.length);
imageView.setImageBitmap(bitmap1);
break;
}
};
The logcat shows the following:
01-25 14:49:31.800: D/dalvikvm(9451): Debugger has detached; object registry had 1 entries
01-25 14:49:38.380: V/BluetoothSocket.cpp(9451): initSocketNative
01-25 14:49:38.380: V/BluetoothSocket.cpp(9451): ...fd 40 created (RFCOMM, lm = 26)
01-25 14:49:38.380: V/BluetoothSocket.cpp(9451): initSocketFromFdNative
01-25 14:49:40.420: D/BluetoothUtils(9451): isSocketAllowedBySecurityPolicy start : device null
01-25 14:49:41.680: I/System.out(9451): bluetoothSocketInThread failed
01-25 14:49:41.680: V/BluetoothSocket.cpp(9451): abortNative
01-25 14:49:41.680: V/BluetoothSocket.cpp(9451): ...asocket_abort(40) complete
01-25 14:49:41.680: V/BluetoothSocket.cpp(9451): destroyNative
01-25 14:49:41.680: V/BluetoothSocket.cpp(9451): ...asocket_destroy(40) complete
Thanks in advance.
Maybe you can try adding thread.sleep for a second? See this discussion:
"The only way I've been able to fix the problem is by adding a
thread.sleep for a second before closing the connection."
also see dan's two consecutive comments on this thread:
"I was able to get this to run only after separating the calls to
findBT(); openBT();
Otherwise, mmSocket.connect(); throws an exception, “Service discovery
failed”
but if I put findBT() in onCreate() and just use the button for
openBT(); it works fine.
Or, if I make a second button, one for each, it works fine.
Suggestions?"
the excerpts from the second comment:
Set pairedDevices = mBluetoothAdapter.getBondedDevices();
mmDevice = mBluetoothAdapter.getRemoteDevice(“00:06:66:46:5A:91″);
if (pairedDevices.contains(mmDevice))
{
statusText.setText(“Bluetooth Device Found, address: ” + mmDevice.getAddress() );
Log.d(“ArduinoBT”, “BT is paired”);
}
where I entered the address of my Bluetooth device. The original code
finds the device and returns the correct address, but
mmSocket.connect(); generates an exception “java.io.IOException:
Service discovery failed”
Suggestions?