Playing two sounds simultaneously - Android - android

Is it possible to play two sound (mp3) files at the same time? I have tried using two different MediaPlayer objects-
MediaPlayer mediaPlayer;
MediaPlayer mediaPlayer2;
to play the sounds, but that does not work. I cannot use SoundPool either as the sound files in use are around 10MB each (since SoundPool doesn't work well with sound files > 3MB).
Here is some code to get familiar with my situation-
#Override
public void onResume() {
super.onResume();
if(mediaPlayer == null)
{
mediaPlayer = MediaPlayer.create(getActivity().getApplicationContext(), R.raw.song1);
}
if(mediaPlayer2 == null)
{
mediaPlayer2 = MediaPlayer.create(getActivity().getApplicationContext(), R.raw.song2);
}
}
private void startPlaying() {
mediaPlayer.setLooping(true);
mediaPlayer.start();
mediaPlayer2.start();
}
Any suggestions? Is there some way to make this 2 MediaPlayer objects approach work? If not then what other options are there? Code would be helpful!

So playing two audio files simultaneously is definitely an issue so I thought, another way to look at the problem would be to combine two audio files programmatically into one, and play that. That turned out to be simple to implement with WAV files (MP3 and other compressed formats would need to be uncompressed first?). Anyway, here's how I did it:
InputStream is = getResources().openRawResource(R.raw.emokylotheme); // Name of file 1
byte [] bytesTemp2 = fullyReadFileToBytes(new File(
Environment.getExternalStorageDirectory().getAbsolutePath()+
"/Kylo Ren/"+filename+"_morphed.wav")); // Name of file 2
byte [] sample2 = convertInputStreamToByteArray(is);
byte[] temp2 = bytesTemp2.clone();
RandomAccessFile randomAccessFile2 = new RandomAccessFile(new File(
Environment.getExternalStorageDirectory().getAbsolutePath()+
"/Kylo Ren/"+filename+"_morphed.wav"), "rw");
//seek to skip 44 bytes for WAV formats
randomAccessFile2.seek(44);
for (int n = 0; n < bytesTemp2.length; n++)
{
bytesTemp2[n] = (byte) ((temp2[n] + (sample2[n])));
}
randomAccessFile2.write(bytesTemp2);
randomAccessFile2.close();
And here are the support functions:
public byte[] convertInputStreamToByteArray(InputStream inputStream)
{
byte[] bytes= null;
try
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte data[] = new byte[1024];
int count;
while ((count = inputStream.read(data)) != -1)
{
bos.write(data, 0, count);
}
bos.flush();
bos.close();
inputStream.close();
bytes = bos.toByteArray();
}
catch (IOException e)
{
e.printStackTrace();
}
return bytes;
}
byte[] fullyReadFileToBytes(File f) throws IOException {
int size = (int) f.length();
byte bytes[] = new byte[size];
byte tmpBuff[] = new byte[size];
FileInputStream fis= new FileInputStream(f);
try {
int read = fis.read(bytes, 0, size);
if (read < size) {
int remain = size - read;
while (remain > 0) {
read = fis.read(tmpBuff, 0, remain);
System.arraycopy(tmpBuff, 0, bytes, size - remain, read);
remain -= read;
}
}
} catch (IOException e){
throw e;
} finally {
fis.close();
}
return bytes;
}
In essence, what the code does is: It gets the bytes of the two audio files (one is within the app in R.raw and the other is in the external storage directory), sums them up, and writes the new bytes to another file.
The issue with this code is that it generates some amount of background noise. It isn't a lot but I believe the summing up of the bytes at certain points (maybe extremas?) leads to the noise. If someone knows how to fix this, could you edit the answer and let me know.
P.S. this was for an open source voice changer app with dramatic background noise effects called Kylo Ren Voice Changer (https://github.com/advaitsaravade/Kylo-Ren-Voice-Changer)

I have used two instances of MediaPlayer in a Service. My code is similar to yours. I had some problems but finally solved it. Please check my answer here Unable to play two MediaPlayer at same time in Nexus 5
If you still have problems, please put your full code and the logcat error.

You can also try to create two fragments and each play a sound.
I have another problem if i played an mp3 file, then click the back button and then start the activity again and ican play the same file again. You can will read Android Mediaplayer multiple instances when activity resumes play sound in the same time

Related

Get inverse of bytes for audio that it becomes phase out of original audio signal

I want eliminate audio by playing original audio and its inverse at the same time. I have the byte array of the audio but I cannot find a way to take inverse of that byte array. I want to shift the phase to 180. So that it becomes inverse of the original signal. Hence silence.
I followed this link https://www.tutorialspoint.com/android/android_audio_capture.htm to record audio. To convert audio to bytes I followed How to convert video/audio file to byte array and vice versa in android.? this question. And the best answer to this question Android - Playing mp3 from byte[] to play the bytes. I followed http://programminglinuxblog.blogspot.com/2014/07/how-to-flip-all-bits-in-bytearray-java.html link to get inverse. But when I play audio with only the inverse bytes nothing plays.
byte[] toFlip, flipped;
try {
toFlip = convertAudioToBytes();
BitSet set = BitSet.valueOf(toFlip);
set.flip(0, set.length());
flipped = set.toByteArray();
Toast.makeText(MainActivity.this, "Inveresed Successfully", Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "Inveresed Failed" + e, Toast.LENGTH_LONG).show();
System.out.println("Inveresed Failed" + e);
}
public byte[] convertAudioToBytes() throws IOException {
FileInputStream fis = new FileInputStream(AudioSavePathInDevice);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
for (int readNum; (readNum = fis.read(b)) != -1; ) {
bos.write(b, 0, readNum);
}
byte[] bytes = bos.toByteArray();
return bytes;
}
private void playMp3(byte[] mp3SoundByteArray) {
try {
// create temp file that will hold byte array
File tempMp3 = File.createTempFile("kurchina", "mp3", getCacheDir());
tempMp3.deleteOnExit();
FileOutputStream fos = new FileOutputStream(tempMp3);
fos.write(mp3SoundByteArray);
fos.close();
// resetting mediaplayer instance to evade problems
mediaPlayer.reset();
// In case you run into issues with threading consider new instance like:
// MediaPlayer mediaPlayer = new MediaPlayer();
// Tried passing path directly, but kept getting
// "Prepare failed.: status=0x1"
// so using file descriptor instead
FileInputStream fis = new FileInputStream(tempMp3);
mediaPlayer.setDataSource(fis.getFD());
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException ex) {
String s = ex.toString();
ex.printStackTrace();
}
}
It should play the inverse when flipped byte array is played. But nothing plays.

How to break a video into pieces using android?

I want java code to create partition of video of specific size.
e.g. Consider a video of size 20mb and I want peices of 5 mb each. so we get 4 parts.
I have used code below but it only creates .MP4 file it is not creating video file.
public static void divideFile(File f) {
int partCounter = 1;//I like to name parts from 001, 002, 003,
//you can change it to 0 if you want 000, 001,003
int sizeOfFiles = 1024 * 1024;// 1MB
byte[] buffer = new byte[sizeOfFiles];
String fileName = f.getName();
//try-with-resources to ensure closing stream
try (FileInputStream fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis)) {
int bytesAmount = 0;
while ((bytesAmount = bis.read(buffer)) > 0) {
//write each chunk of data into separate file with different number in name
String filePartName = String.format("%s.%03d", fileName, partCounter++);
File newFile = new File(f.getParent(), filePartName);
try (FileOutputStream out = new FileOutputStream(newFile)) {
out.write(buffer, 0, bytesAmount);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I think you want each part to be a playable video itself - in this case each part needs the correct metadata headers to allow a player to handle it properly.
Breaking the video up just by bytes will mean that metadata is not present or not correct in any of the chunks.
You can use ffmpeg to do this correctly with the following command (for mp4):
ffmpeg -I videoPath -ss startTime -t endTime -c copy outputVideoChunk.mp4
There are several ways to use ffmpeg within an Android app but one of the easiest is to use a well supported wrapper library like:
https://github.com/WritingMinds/ffmpeg-android-java

Accessing the output video while recording

In short, I'm looking for a way to get the byte stream from the camera while recording video.
The aim is to continuously record while saving certain portions of the current recording without stopping the actual recording process to access the output file. Is this even possible, or will I need to actually stop the recording and save it for it be playable?
I've seen projects and open source library's that allow live streaming from the camera to a server via a local socket and the ParcelFileDescriptor class, so I assume (maybe incorrectly) that the recorder byte stream must be accessible somehow.
Any suggestions or help would be greatly appreciated.
Set output file to FileDescriptor:
mRecorder.setOutputFile(getStreamFd());
Then use this function:
private FileDescriptor getStreamFd() {
ParcelFileDescriptor[] pipe = null;
try {
pipe = ParcelFileDescriptor.createPipe();
new TransferThread(new ParcelFileDescriptor.AutoCloseInputStream(pipe[0]),
new FileOutputStream(getOutputFile())).start();
} catch (IOException e) {
Log.e(getClass().getSimpleName(), "Exception opening pipe", e);
}
return (pipe[1].getFileDescriptor());
}
private File getOutputFile() {
return (new File(Environment.getExternalStorageDirectory().getPath().toString() + "/YourDirectory/filename"));
}
New thread code:
static class TransferThread extends Thread {
InputStream in;
FileOutputStream out;
TransferThread(InputStream in, FileOutputStream out) {
this.in = in;
this.out = out;
}
#Override
public void run() {
byte[] buf = new byte[8192];
int len;
try {
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.flush();
out.getFD().sync();
out.close();
} catch (IOException e) {
Log.e(getClass().getSimpleName(),
"Exception transferring file", e);
}
}
}
Don't forget to add persmissions to your manifest file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I had a similiar problem and wanted to record H264 in an MP4 file while accessing the H264 NAL units camera byte stream (redirect it to libRTMP). The following example helped alot (requires at least Android 4.3):
http://bigflake.com/mediacodec/ <- the CameraToMpegTest.java and "Android Breakout game recorder patch" examples
Basically, Androids MediaCodec class provides low level access to the device encoders/decoders. Take a look at the function drainEncoder() of the examples above:
the video data is send to MediaMuxer to create an output file
you can easily access the H264 NAL units from encodedData ByteBuffer and process them the way you want
Example:
int old_pos = encodedData.position();
encodedData.position(0);
byte[] encoded_array = new byte[encodedData.remaining()];
encodedData.get(encoded_array);
encodedData.position(old_pos);

How to copy large files in Android?

I am trying to copy a large pdf-file (3.7 mb) from my raw-folder to the external cache directory.
I a using the following piece of code:
int i = 0;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
InputStream input = getResources().openRawResource(pdfs[i]);
File file = new File(Environment.getExternalStorageDirectory(), "/Android/data/eu.app/cache/" + pdfNames[i]);
if(!file.exists())
{
try
{
new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/eu.app/cache").mkdirs();
FileOutputStream fos = new FileOutputStream(file.toURI().getPath(), false);
OutputStream os = new BufferedOutputStream(fos);
byte[] buffer = new byte[1024];
int byteRead = 0;
while ((byteRead = input.read(buffer)) != -1) {
os.write(buffer, 0, byteRead);
}
fos.close();
}
catch(Exception ex)
{
Log.d("storage", ex.getMessage());
}
}
}
else
{
}
I don't get any errors, but the output-file is a few bytes smaller than the original and cannot be opened.
What do I need to do to fix this?
I think the main issue is that you close fos while you should close os. You also need to put the close operation in a finally block.
Update (now with a full keyboard ;)): You close the file stream (fos) before the buffered stream is flushed. What you should do is to close the buffered stream (os), and that will in turn flush its buffer and write those bytes that are missing, and then it will automatically close the underlying file stream. To fix it change fos.close() into os.close().
In addition, to make sure that you always close the stream you should place the close operation in a finally block. A typical pattern is the following:
BufferedInputStream in = null;
try {
in = new BufferedInputStream(anInputStream);
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream(aFile));
// Read and write what you should write
}
finally {
if (out != null) out.close();
}
} finally {
if (in != null) in.close();
}
You can easily add an input stream, but be careful to make sure all streams are closed. This can be handled by nesting finally blocks or nesting try-catch blocks inside the finally block.
Either you throw an IOException from this method and handle it outside (often preferred), or you wrap the above code in a new try-catch statement and handle it there. However, handling it within the method mixes UI with logic and the code is often clearer separating UI and logic.
A final note: 1024 is rather small. Play with different values. On the other hand the buffered stream will handle the buffering for you.
I've been using this function for reading from one stream to another for a few years and have never had any problems with the resulting file. Just open the source and target files as you are and pass their respective streams into this function:
public static void streamToStream(InputStream is, OutputStream os) {
int count = 0;
try {
while(count != -1) {
byte[] bytes = new byte[2048];
count = is.read(bytes);
if(count == -1) {
continue;
}
os.write(bytes, 0, count);
bytes = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}

How to encode Recorded voice to ogg vorbis?

I have recorded voice with android AudioRecord and I would like to convert it to ogg vorbis as it is patent free. I have try vorbis-java beta, but it seem not work or I make some mistake.
Here are my code :
int frequency = 44100;
int channel = AudioFormat.CHANNEL_IN_STEREO;
int mAudioSource = MediaRecorder.AudioSource.MIC;
int mAudioEncoder = AudioFormat.ENCODING_PCM_16BIT;
try {
final File outputFile = new File(mOutputPath);
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile)));
int bufferSize = AudioRecord.getMinBufferSize(frequency, channel, mAudioEncoder);
AudioRecord audioRecord = new AudioRecord(mAudioSource, frequency, channel, mAudioEncoder, bufferSize);
short[] buffer = new short[bufferSize];
audioRecord.startRecording();
while (isRecordStart) {
int bufferReadResult = audioRecord.read(buffer, 0, bufferSize);
for(int i = 0; i < bufferReadResult; i++) {
dos.writeShort(buffer[i]);
}
}
audioRecord.stop();
dos.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
I save it to a file with extension wav and use example of vorbis-java to encode, but output is only zzz.......
How to encode this to ogg vorbis in android?
I think i read this question a few weeks ago and was also super frustrated. I ended up writing the needed ndk wrapper to use Xiph.org's stuff. The only catch is that in order to make it run well, I had to enable floating point instructions. Emulators don't have floating point, so it'll crash the emulator. Run it on pretty much any phone, though, and you'll be good to go. It's designed to emulate a FileInputStream and FileOutputStream for interfacing with the vorbis files.
https://github.com/nwertzberger/libogg-vorbis-android
You seem to write raw audio data into a file instead of wav format. Wav format does have headers, not just audio data.
Note: Don't use vorbis-java, but compile from libogg and libvorbis sources at http://www.xiph.org/downloads/
Use android NDK to compile them for embedding in your apk file.
Then you can call the native code from your app to encode the audio data.

Categories

Resources