I am trying to play a wav file of size 230mb and 20 min whose properties are as below:
ffmpeg -i 1.wav
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, stereo, s16, 1411 kb/s
I am learning how to use audiotrack.
I found two solutions to play this audio play using audiotrack.
Solution 1: the following plays the audio
int frequency = 44100;
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioTrack.getMinBufferSize(frequency, channelConfiguration,audioEncoding);
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, frequency,
channelConfiguration, audioEncoding, bufferSize,
AudioTrack.MODE_STREAM);
int count = 0;
byte[] data = new byte[bufferSize];
try{
FileInputStream fileInputStream = new FileInputStream(listMusicFiles.get(0).listmusicfiles_fullfilepath);
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
audioTrack.play();
while((count = dataInputStream.read(data, 0, bufferSize)) > -1){
audioTrack.write(data, 0, count);
}
audioTrack.stop();
audioTrack.release();
dataInputStream.close();
fileInputStream.close();
}
catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Second Solution: Playing noise
int frequency = 44100;
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioTrack.getMinBufferSize(frequency, channelConfiguration,audioEncoding);
short[] audiodata = new short[bufferSize];
try {
DataInputStream dis = new DataInputStream(
new BufferedInputStream(new FileInputStream(
listMusicFiles.get(0).listmusicfiles_fullfilepath)));
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, frequency,
channelConfiguration, audioEncoding, bufferSize,
AudioTrack.MODE_STREAM);
audioTrack.play();
while (dis.available() > 0) {
int i = 0;
while (dis.available() > 0 && i < audiodata.length) {
audiodata[i] = dis.readShort();
i++;
}
audioTrack.write(audiodata, 0, audiodata.length);
}
dis.close();
} catch (Throwable t) {
Log.e("AudioTrack", "Playback Failed");
}
I am new to short sample and byte samples. I tried to understand but it not so easy.
I could understand the first solution is using byte sample and the second solution is using short samples.
So why is the second solution not working.
The default size of a short type is two bytes. You might have a look at this documentation as well.
The audio track has a recommended buffer size and sample rate which can be found using the way suggested here in this answer. Please have a look.
However, it is important to play the audio using the recommended sample rate which is 44100 Hz in your case and the recommended buffer size that you get using the following code segment.
AudioTrack.getMinBufferSize(frequency, channelConfiguration, audioEncoding)
In your implementation with short array, the buffer size is doubled and hence its creating noises in case of playing the audio. I would suggest, you might consider changing the buffer size by dividing the size by two in your implementation using short.
short[] audiodata = new short[(int) bufferSize / 2];
Hope you have understood the problem.
Related
I am trying to send audio between windows and android, I was successfully able to do that windows to windows but when I stream audio from android, it produces a white noise only. I think it is an issue with the AudioFormat in android and Windows because when I changed the sample Bits to 8 I guess, I heard the voice in one side of my headphones but then it went away too.
On Android Side
int BUFFER_MS = 15; // do not buffer more than BUFFER_MS milliseconds
int bufferSize = 48000 * 2 * BUFFER_MS / 1000;
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 48000, 2,
AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM);
byte[] buffer = new byte[bufferSize];
int bytesRead;
audioTrack.play();
while (socket.isConnected()) {
bytesRead = inputStream.read(buffer, 0, buffer.length);
audioTrack.write(buffer,0,bytesRead);
}
On Windows Side
AudioFormat format = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
// checks if system supports the data line
if (!AudioSystem.isLineSupported(info)) {
throw new LineUnavailableException(
"The system does not support the specified format.");
}
TargetDataLine audioLine = AudioSystem.getTargetDataLine(format);
audioLine.open(format);
audioLine.start();
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while (socket.isConnected()) {
bytesRead = audioLine.read(buffer, 0, buffer.length);
outputStream.write(buffer,0,bytesRead);
}
and getAudioFormat function is
AudioFormat getAudioFormat() {
float sampleRate = 48000;
int sampleSizeInBits = 16;
int channels = 2;
boolean signed = true;
boolean bigEndian = true;
return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,
bigEndian);
}
Only hearing a white noise, if someone can help please do.
Okayyyy So I found out the problem. I just had to put bigEndian to false -_-
It's the byte order difference. I don't understand why it's different in android and pc but seems like it does the trick.
I am Developing an app in android live streaming. I am able to stream the live videos to the YouTube channel. But the problem was, getting no audio to that live streaming video.
My code will like below
private static final int frequency= 44100;
public void recordThread() {
Log.d(MainActivity.APP_NAME, "recordThread");
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
int channelConfiguration = AudioFormat.CHANNEL_IN_STEREO;
int bufferSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding);
Log.i(MainActivity.APP_NAME, "AudioRecord buffer size: " + bufferSize);
// 16 bit PCM stereo recording was chosen as example.
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency, channelConfiguration,
audioEncoding, bufferSize);
recorder.startRecording();
// Make bufferSize be in samples instead of bytes.
bufferSize /= 2;
short[] buffer = new short[bufferSize];
while (!cancel) {
int bufferReadResult = recorder.read(buffer, 0, bufferSize);
// Utils.Debug("bufferReadResult: " + bufferReadResult);
if (bufferReadResult > 0) {
frameCallback.handleFrame(buffer, bufferReadResult);
} else if (bufferReadResult < 0) {
Log.w(MainActivity.APP_NAME, "Error calling recorder.read: " + bufferReadResult);
}
}
recorder.stop();
Log.d(MainActivity.APP_NAME, "exit recordThread");
}
please some suggest me the solution to get out of this issue.
Search in github. There you will find a sample project(yasea) for audio encoding. Intermix those two projects, you will get the solution.
How can on Android the bits per sample be changed from 16 bit to 8 bit (or other bitrates) in a AudioRecord object when recording in wav format?
This doesn't work (as discussed for example here: Using AudioRecord with 8-bit encoding in android):
private static int RECORDER_AUDIO_ENCODING =
AudioFormat.ENCODING_PCM_8BIT; -->ERROR: Invalid Audio Format.
bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING);
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,RECORDER_SAMPLERATE,
RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING, bufferSize);
With the header:
private void WriteWaveFileHeader(
FileOutputStream out, long totalAudioLen,
long totalDataLen, long longSampleRate, int channels,
long byteRate) throws IOException {
byte[] header = new byte[44];
header[0] = 'R'; // RIFF/WAVE header
...header content...
header[32] = (byte) (2 * 16 / 8); // block align
header[33] = 0;
header[34] = (byte)RECORDER_BPP; // bits per sample, set to 8
...header content...
out.write(header, 0, 44);
}
You need to record 16 Bit samples by using AudioFormat.ENCODING_PCM_16BIT because 8 Bit encoding is not generally working on Android devices.
Then convert your 16 Bit buffer to 8 Bit on the fly prior to writing it into a wave sound file. But because 8 Bit wave files use unsigned integers (0-255) with silence being 128 instead of 0, my suggested conversion corrects for that. The following is just a code skeleton:
// Your source above already defined a value for bufferSize and the recorder object
sampleBufferShorts = new short[bufferSize];
sampleBufferBytes = new short[bufferSize];
int numberOfShortsRead = recorder.read(samleBufferShorts, 0, bufferSize);
if (numberOfShortsRead != ERROR_INVALID_OPERATION && numberOfShortsRead != ERROR_BAD_VALUE) {
for (int i = 0 ; i < numberOfShortsRead ; ++i)
sampleBufferBytes[i] = (byte)((sampleBufferShorts[i]>>8)+128);
}
See https://stackoverflow.com/a/18777515/1986583 for a useful explanation why additional dithering would improve the resulting quality.
Its not possible, you'll have to postprocess your .wav file.
I am trying to record sound (using Android's AudioRecord), and simultaneously play the recorded sound (using Android's AudioTrack). I initialize the recorder and output track as follows:
int buffersize = 2*AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, buffersize);
AudioTrack output = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT), AudioTrack.MODE_STREAM);
Now when I press the start button this method is called:
int buffersize = 5*AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
Thread recordThread = new Thread(new Runnable() {
public void run() {
recorder.startRecording();
output.play();
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() < startTime + 3000) { // Always record 3 seconds
byte[] myBuffer = new byte[buffersize];
recorder.read(myBuffer, 0, buffersize);
output.write(myBuffer, 0, buffersize);
}
recorder.stop();
recorder.release();
output.stop();
output.release();
stopThread(); // void stopThread() {recordThread = null;}
}
}
recordThread.start();
Now all I hear is noise, nothing like the music I am recording.
What am I doing wrong? Please help.
Thanks in advance,
Jeroen D.
EDIT:
I have found the problem, namely that the rate (8000) is way too low. I tried it with 44100 on a real phone (because the android emulator supports only 8000), and now the quality is fine. Thanks for the help.
in my application, I need to direct sound from microphone directly to speaker. No other actions.
I found a way to direct sound from microphone to earpiece by playing a file and setting speaker off. So I guess speaker can work similarly. However I don' know how to get rid of the playing file thing. Thank you.
speaker() {
m_audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
m_audioManager.setSpeakerphoneOn(true); // not needed I think
//m_audioManager.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL); earpiece need this?
setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
m_audioManager.setMode(AudioManager.MODE_IN_CALL);
use AudioRecord & AudioTrack to record & play (change to ..._MUSIC if speaker needed
static final int bufferSize = 200000;
final short[] buffer = new short[bufferSize];
short[] readBuffer = new short[bufferSize];
public void run() {
isRecording = true;
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
int buffersize = AudioRecord.getMinBufferSize(11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
arec = new AudioRecord(MediaRecorder.AudioSource.MIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, buffersize);
atrack = new AudioTrack(AudioManager.STREAM_VOICE_CALL, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, buffersize, AudioTrack.MODE_STREAM);
atrack.setPlaybackRate(11025);
byte[] buffer = new byte[buffersize];
arec.startRecording();
atrack.play();
while(isRecording) {
arec.read(buffer, 0, buffersize);
atrack.write(buffer, 0, buffer.length);
}
}