I am using AudioTrack library to play pcm samples that are being streamed via wifi. The problem is the playback is very choppy while playing on Lenovo K900 (4.1.2), whereas it is seamless while playing on OnePlusOne (Marshmallow 6.0.1 cyanogen) handset.
To rule out streaming delay I first loaded the entire stream in an array then played the audio by looping over the pre-populated array. Still things do not improve at all.
Now K900 is running Android 4.1.2 whereas the android sdk I used is for API23, I mean when I open the definition of AudioTrack class it open the class file of API23. Is it causing any problem?
int bufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_8BIT);
if (bufferSize == AudioTrack.ERROR || bufferSize == AudioTrack.ERROR_BAD_VALUE) {
bufferSize = SAMPLE_RATE * 2;
}
int readBytes;
int bufSize=2123880;//size of the file being streamed
byte[] buffer=new byte[bufSize];
//bufferSize*=2;
DataInputStream in = new DataInputStream(socket.getInputStream());
readBytes=0;
while(true) {
try {
if(in.available()>0){
readBytes+=in.read(buffer, readBytes, in.available());
// audioTrack.write(buffer,0,readBytes);
}else{
break;
}
} catch (SocketTimeoutException s) {
System.out.println("Socket timed out!");
//audioTrack.release();
break;
} catch (IOException e) {
e.printStackTrace();
//audioTrack.release();
break;
}
}
in.close();
readBytes=0;
AudioTrack audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
SAMPLE_RATE,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_8BIT,
bufferSize,
AudioTrack.MODE_STREAM);
audioTrack.play();
while(readBytes<bufSize){
readBytes+=audioTrack.write(buffer,readBytes,bufferSize);
}
audioTrack.release();
I tested with samples having different sampling rate ranging from 19250hz to 44100hz. For all cases K900 strong text is playing choppy whereas Oneplus one plays smooth. I dont think that K900 is underpowered to pull up this easy job.
Kindly assist.
EDIT
Here is the code I intend to use:
try {
//dataInputStream = new DataInputStream(socket.getInputStream());
//response = dataInputStream.readUTF();
int bufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_8BIT);
if (bufferSize == AudioTrack.ERROR || bufferSize == AudioTrack.ERROR_BAD_VALUE) {
bufferSize = SAMPLE_RATE * 2;
}
int readBytes;
byte[] buffer = new byte[bufferSize];
bufferSize = bufferSize * 2;
AudioTrack audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
SAMPLE_RATE,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_8BIT,
bufferSize,
AudioTrack.MODE_STREAM);
audioTrack.play();
DataInputStream in = new DataInputStream(socket.getInputStream());
while (true) {
try {
if (in.available() > 0) {
readBytes = in.read(buffer, 0, buffer.length);
audioTrack.write(buffer, 0, readBytes);
}
} catch (SocketTimeoutException s) {
System.out.println("Socket timed out!");
audioTrack.release();
in.close();
socket.close();
break;
} catch (IOException e) {
e.printStackTrace();
audioTrack.release();
in.close();
socket.close();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Thanks,
Debojit
Related
To produce sound on Android, I am using AudioTrack.
I have been able to produce sine waves, sawtooth waves, square waves but it would be nice to have a more realistic sound.
I found that .wav files were the easiest to play on AudioTrack because they are basically just a sequence of bytes with a header.
So I have got my wav file in the res/raw folder and I tried playing it with this code :
public void writeWav(){
byte[] byteData = null;
InputStream is = getResources().openRawResource(R.raw.high);
byteData = new byte[mBufferSize];
try {
is.read(byteData);
is.close();
}
catch (FileNotFoundException e) {}
catch (IOException e) {}
mAudioTrack.write(byteData, 0, byteData.length);
}
But all I get is noise. I realize there are lots of questions about AudioTrack and wav files, but I couldn't find an answer to my noise problem.
Use this method to play sound using audioTrack. It works for me
public void playAudioTrack() {
int sampleFreq = 16000;
File file = new File("--filePath--");
int shortSizeInBytes = Short.SIZE / Byte.SIZE;
int minBufferSize = AudioTrack.getMinBufferSize(sampleFreq, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
int bufferSizeInBytes = (int)(file.length() / shortSizeInBytes);
final AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, sampleFreq,
AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize,
AudioTrack.MODE_STREAM);
int i = 0;
byte[] s = new byte[bufferSizeInBytes];
try {
final FileInputStream fin = new FileInputStream("--filePath--");
final DataInputStream dis = new DataInputStream(fin);
at.setNotificationMarkerPosition((int)(file.length() / 2));
at.play();
while ((i = dis.read(s, 0, bufferSizeInBytes)) > -1) {
at.write(s, 0, i);
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
} catch (Exception e) {
}
}
hello I have this code
AudioTrack audioTrack;
public void playAccordeon() {
int minBufferSize = AudioTrack.getMinBufferSize(44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
int bufferSize = 512;
if (audioTrack == null) {
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, minBufferSize,
AudioTrack.MODE_STREAM);
audioTrack.play();
}
int i = 0;
byte[] s = new byte[bufferSize];
try {
InputStream fin = getResources().openRawResource(R.raw.accordeon);
while ((i = fin.read(s)) != -1) {
audioTrack.write(s, 0, i);
}
fin.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
its works but there is one problem, when I play sound first time it plays fine, but second and third.. play have sound like "click" (I tried many sound files)
what to do? thanks
I don't know how to play live wave audio stream through socket. Now I have got the socket audio stream. the stream format :
wav format header +pcm data
wav format header +pcm data
wav format header +pcm data
So how do i parse the live audio stream to play in the AudioTrack class in android. Thanks.
Here is my code :
private void PlayAudio(int mode)
{
if(AudioTrack.MODE_STATIC != mode && AudioTrack.MODE_STREAM != mode)
throw new InvalidParameterException();
long bytesWritten = 0;
int bytesRead = 0;
int bufferSize = 0;
byte[] buffer;
AudioTrack track;
Socket socket=null;
DataInputStream dIn=null;
bufferSize = 55584; // i donnt know how much the buffer size should be. 55584 is the size that i got first from the socket stream. maybe the buffer size is setted wrong.
//sample rate 16khz,channel: mono sample bits:16 bits channel:1
bufferSize = AudioTrack.getMinBufferSize(16000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
buffer = new byte[bufferSize];
track = new AudioTrack(AudioManager.STREAM_MUSIC, 16000,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
bufferSize, mode);
// in stream mode,
// 1. start track playback
// 2. write data to track
if(AudioTrack.MODE_STREAM == mode)
track.play();
try
{
socket = new Socket("192.168.11.123", 8081);
dIn = new DataInputStream(socket.getInputStream());
// dIn.skipBytes(44);
}
catch (Exception e)
{
e.printStackTrace();
}
try
{
do
{
long t0 = SystemClock.elapsedRealtime();
try
{
bytesRead = dIn.read(buffer, 0, buffer.length);
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (NullPointerException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
bytesWritten += track.write(buffer, 0, bytesRead);
Log.e("debug", "WritesBytes "+bytesRead);
} while (dIn.read() != -1);
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I got mute when i running an activity, but i can hear some music intermittently in debug mode but it is noisy. Could you please help me ?
the server send the stream 100ms interval:
audio format : //sample rate 16khz,channel: mono sample bits:16 bits channel:1
When I play a file with the following code:
private void PlayAudioFileViaAudioTrack(int ResId) throws IOException {
int intSize = android.media.AudioTrack.getMinBufferSize(11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, intSize,
AudioTrack.MODE_STREAM);
int count = 256 * 1024; // 256 kb
byte[] byteData = null;
byteData = new byte[(int) count];
InputStream in = null;
AssetFileDescriptor fd = null;
fd = mResources.openRawResourceFd(ResId);
in = mResources.openRawResource(ResId);
int bytesRead = 0, amount = 0;
int size = (int) fd.getLength();
at.play();
while (bytesRead < size) {
amount = in.read(byteData, 0, count);
if (amount != -1) {
at.write(byteData, 0, amount);
}
}
in.close();
at.stop();
at.release();
}
The only thing I hear is static, white noise. I've checked that my .wav file has the same properties (samplerate,bitrate). I don't have to much knowledge about raw audio data(PCM), so I was wondering if anyone could see what's wrong with my code.
from your code i can see that you just read data from the wav file and just import them to the AudioTrack. Wav files have a small header as you can see here https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ So you have to skip the header and point your file descriptor at the right place where the actual audio data are.
Also when you playing an audio file and you are dealing with byte operations you should take care of the Endianess. Take a look here Using AudioTrack in Android to play a WAV file
Below my code (some checks and the WAV header skip are missing) that works in both Nexus One and Galaxy S with a wav file with frequency 8000Hz and 16 bit encoding.
public void playWav(){
int minBufferSize = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
int bufferSize = 512;
AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
String filepath = Environment.getExternalStorageDirectory().getAbsolutePath();
int i = 0;
byte[] s = new byte[bufferSize];
try {
FileInputStream fin = new FileInputStream(filepath + "/REFERENCE.wav");
DataInputStream dis = new DataInputStream(fin);
at.play();
while((i = dis.read(s, 0, bufferSize)) > -1){
at.write(s, 0, i);
}
at.stop();
at.release();
dis.close();
fin.close();
} catch (FileNotFoundException e) {
// TODO
e.printStackTrace();
} catch (IOException e) {
// TODO
e.printStackTrace();
}
}
That looks WAY more complicated than what I did. I played sounds using this. I think .wav files would work just as well.
MediaPlayer mpPlayProgram = new MediaPlayer();
mpPlayProgram.setDataSource("/sdcard/file.mp3");
mpPlayProgram.prepare();
mpPlayProgram.start();
mpPlayProgram.release();
For static resources, it's even easier:
MediaPlayer mpStart = MediaPlayer.create(this, resID);
mpStart.start();
mpStart.release();
If you have saved file in wav format and want to play it using AudioTrack then follow this code:
File file=new File(Environment.getExternalStorageDirectory()+"/AudioRecorder/fahim.wav");
InputStream is;
DataInputStream dis = null ;
BufferedInputStream bis;
try
{
is = new FileInputStream(file);
bis = new BufferedInputStream(is, 8000);
dis = new DataInputStream(bis); // Create a DataInputStream to read the audio data from the saved file
}
catch (FileNotFoundException e1)
{
ShowToast("fILE NOT FOUND:"+e1.getMessage());
}
int i = 0; // Read the file into the "music" array
music=new byte[(int) file.length()];
try
{
while (dis.available() > 0)
{
music[i] = dis.readByte(); // This assignment does not reverse the order
i++;
}
}
catch (IOException e)
{
ShowToast("I/O Exception:"+e.getMessage());
}
try {dis.close();} catch (IOException e) {e.printStackTrace();}
int minBufferSize = AudioTrack.getMinBufferSize(11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
at.play();
ShowToast("size:"+music.length);
//*/
at.write(music, 0, music.length);
i try and play an mp3 file in my SDCard for my Android emulator but all that comes out is some weird buzzing noise. I made sure the sample rate is 44.1k hz i don't know what else could be wrong
if(AudioTrack.MODE_STATIC != mode && AudioTrack.MODE_STREAM != mode)
throw new InvalidParameterException();
String audioFilePath = "/sdcard/test.mp3";
long fileSize = 0;
long bytesWritten = 0;
int bytesRead = 0;
int bufferSize = 0;
byte[] buffer;
AudioTrack track;
File audioFile = new File(audioFilePath);
fileSize = audioFile.length();
if(AudioTrack.MODE_STREAM == mode)
{
bufferSize = 8000;
}
else
{// AudioTrack.MODE_STATIC
bufferSize = (int)fileSize;
}
buffer = new byte[bufferSize];
track = new AudioTrack(AudioManager.STREAM_MUSIC,/* this is for pcm*/ /*22050*/ /*this is for mp3*/ 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_DEFAULT/*AudioFormat.ENCODING_PCM_16BIT*/,
bufferSize, mode);
// in stream mode,
// 1. start track playback
// 2. write data to track
if(AudioTrack.MODE_STREAM == mode)
track.play();
FileInputStream audioStream = null;
try {
audioStream = new FileInputStream(audioFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while(bytesWritten < fileSize)
{
try {
bytesRead = audioStream.read(buffer, 0, bufferSize);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bytesWritten += track.write(buffer, 0, bytesRead);
}
// in static mode,
// 1. write data to track
// 2. start track playback
if(AudioTrack.MODE_STATIC == mode)
track.play();
It's correct that you hear strange noise, since you need to decode the MP3 first before
you feed it to an AudioTrack! AudioTrack only plays raw PCM audio.
You should use android.media.MediaPlayer to play mp3 audio file