I try to get raw data in PCM format form fm radio source. I do this:
int bufSize = AudioRecord.getMinBufferSize(SAMPLE_RATE_16kHz, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
mRecorder = new AudioRecord(AudioSource.FM_RX, SAMPLE_RATE_16kHz, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufSize);
mBuffer = new short[bufSize / 2];
mRecorder.startRecording();
and when I call in a loop:
int ret = mRecorder.read(mBuffer, 0, mBuffer.length);
the value in ret is 0 and buffer is empty.
But if I change AudioSource.FM_RX to AudioSource.MIC I can get data form microphone. What I do wrong?
AudioSource.FM_RX might be available via CyanogenMod but not in the standard API (see e.g. this question).
Related
I was trying to record the sound from the mic. The sound is sampled against the tone running in background.
To make it clear i want to run a tone in background and when i make some noise from microphone this should be mixed with the background tone that is already playing.
The final output should be a mix of the tone played and the signals from the microphone which is the noise. How can i achieve this.
I was referring to the post Android : recording audio using audiorecord class play as fast forwarded in stackoverflow to record data from microphone. But i need to record the background tone as well as the microphone input.
public class StartRecording {
private int samplePerSec = 8000;
public void Start(){
stopRecording.setEnabled(true);
bufferSize = AudioRecord.getMinBufferSize(samplePerSec, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
audioRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, this.samplePerSec, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize * 10);
audioRecorder.startRecording();
isRecording = true;
while (isRecording && audioRecorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING)
{
short recordedData[] = new short[bufferSize];
audioRecorder.read(recordedData, 0, recordedData.length); // Reading from the audiorecorder
byte[] bData = shortTobyte(recordedData);
}
}
}
private byte[] shortTobyte(short[] recordedData) {
int tempBuff = recordedData.length;
byte[] bytes = new byte[tempBuff * 10];
for (int i = 0; i < tempBuff; i++) {
bytes[i * 2] = (byte) (recordedData[i] & 0x00FF);
bytes[(i * 2) + 1] = (byte) (recordedData[i] >> 8);
recordedData[i] = 0;
}
return bytes;
}
Thanks in advance...
You have to use AudioTrack and AudioRecord simulteanously.
Then all buffers from AudioRecord must be mixed to your tone (there are some algo on google for mixing 2 audio signals) and written in the AudioTrack.
You will have latency and some problems with echo if you don't use a headset.
I'm trying to read raw data from mic by following code:
short buffer[] = new short[AudioRecord.getMinBufferSize(8000,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT)];
Log.d("O_o",""+buffer.length);
AudioRecord rec = new AudioRecord(
MediaRecorder.AudioSource.MIC, 8000,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, buffer.length);
rec.startRecording();
int read = rec.read(buffer, 0, buffer.length);
for (int i = 0; i < read; i++) {
Log.d("O_o",i+" "+buffer[i]);
}
rec.stop();
rec.release();
But buffer always filled with 257 values.
What's wrong ?
UDP: look like i'ts initital values. Calling read() in cycle causes normal values.
You definitely should take a look at this question + answer. It shows some code which would improve your code very much.
Basically, your problem is that you're trying to read it synchronously. The Audio process will usually have to be implemented asynchronously and you'll be getting 256 byte-sized chunks of audio at any one time.
I am trying to read the data from the MIC and process it and store it in a file. But i am not getting any data from the MIC, the buffer is all zeroes.
int MIN_BUF = 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, MIN_BUF);
byte[] pcm_in = new byte[320];
recorder.startRecording();
while(record)
{
int bytes_read = recorder.read(pcm_in, 0, pcm_in.length);
switch(bytes_read)
{
case AudioRecord.ERROR_INVALID_OPERATION:
case AudioRecord.ERROR_BAD_VALUE:
Log.i("Microphone", "Error in reading the data");
break;
default:
print(pcm_in);
break;
}
}
recorder.stop();
recorder.release();
But in the print(pcm), when i printed byte by byte i am getting all zeroes. Some posts are there in stackoverflow with similar issues, but my issue didn't got fixed with that.
Please help me in fixing this.
Thanks & Regards,
SSuman185
print(pcm_in) will show you the actual data. you need to get the pcm_in data to pcm in a loop till you stop recording.
Meaning that your variable record is a boolean right. and you will make it false in another method. so till you make it false recorder.read(pcm_in, 0, pcm_in.length) operation will get the data from your mic and put it into the pcm_in(so you need to be sure that the size of pcm_in is equal to pcm). the bytes_read will be the size of the bytes read in this operation. so you can copy the pcm_in bytes to pcm in a loop that can read whole pcm_in data.
for example:
bytes_read = recorder.read(pcm_in, 0, pcm_in.length);
for(int i=0; i<bytes_read ;i++){
pcm[i] = pcm_in[i];
}
But this is a weird usage. I think your pcm should be as large as the file you need to load in it. and make sure you are addin the pcm_in to it , not overriding. I think this is what you want.
I'm streaming the mic audio between two devices, everything is working but i have a bad echo.
Here what i'm doing
Reading thread
int sampleFreq = 22050;
int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int minBuffer = 2*AudioTrack.getMinBufferSize(sampleFreq, channelConfig, audioFormat);
AudioTrack atrack = new AudioTrack(AudioManager.STREAM_MUSIC,
sampleFreq,
channelConfig,
audioFormat,
minBuffer,
AudioTrack.MODE_STREAM);
atrack.play();
byte[] buffer = new byte[minBuffer];
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
atrack.write(buffer, 0, buffer.length);
atrack.flush();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
break;
}
}
Here the recording thread
int sampleRate = 22050;
int channelMode = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int buffersize = 2*AudioTrack.getMinBufferSize(sampleRate, channelMode, audioFormat);
AudioRecord arec = new AudioRecord(MediaRecorder.AudioSource.MIC,
sampleRate, channelMode,
AudioFormat.ENCODING_PCM_16BIT, buffersize);
buffer = new byte[buffersize];
arec.startRecording();
while (true) {
arec.read(buffer, 0, buffersize);
new Thread( new Runnable(){
#Override
public void run() {
try {
mOutputStream.write(buffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
Am I doing something wrong?
You need echo cancellation logic. Here is what I did on my Arm5 (WM8650) processor (Android 2.2) to remove the echo.
I wrapped Speex with JNI and called echo processing routines before sending PCM frames to encoder. No echo was canceled no matter what Speex settings I tried.
Because Speex is very sensitive to delay between playback and echo frames I implemented a queue and queued all packets sent to AudioTrack. The size of the queue should be roughly equal to the size of internal AudioTrack buffer. This way packet were sent to echo_playback roughly at the time when AudioTrack send packets to the sound card from its internal buffer. The delay was removed with this approach but echo was still not cancelled
I wrapped WebRtc echo cancellation part with JNI and called its methods before sending packets to encoder. The echo was still present but the library obviously was trying to cancel it.
I applied the buffer technique described in P2 and it finally started to work. The delay needs to be adjusted for each device though. Note also that WebRtc has mobile and full version of echo cancellation. The full version substantially slows the processor and should probably be run on ARM7 only. The mobile version works but with lower quality
I hope this will help someone.
Could be this:
bytes = mmInStream.read(buffer);
atrack.write(buffer, 0, buffer.length);
If the buffer remains full from previous call and the new one is not full (so bytes < buffer.length) you re-play hold part of track.
I'm working with Android, trying to make my AudioTrack application play a Windows .wav file (Tada.wav). Frankly, it shouldn't be this hard, but I'm hearing a lot of strange stuff. The file is saved on my phone's mini SD card and reading the contents doesn't seem to be a problem, but when I play the file (with parameters I'm only PRETTY SURE are right), I get a few seconds of white noise before the sound seems to resolve itself into something that just may be right.
I have successfully recorded and played my own voice back on the phone -- I created a .pcm file according to the directions in this example:
http://emeadev.blogspot.com/2009/09/raw-audio-manipulation-in-android.html
(without the backwards masking)...
Anybody got some suggestions or awareness of an example on the web for playing a .wav file on an Android??
Thanks,
R.
I stumbled on the answer (frankly, by trying &^#! I didn't think would work), in case anybody's interested... In my original code (which is derived from the example in the link in the original post), the data is read from the file like so:
InputStream is = new FileInputStream (file);
BufferedInputStream bis = new BufferedInputStream (is, 8000);
DataInputStream dis = new DataInputStream (bis); // Create a DataInputStream to read the audio data from the saved file
int i = 0; // Read the file into the "music" array
while (dis.available() > 0)
{
music[i] = dis.readShort(); // This assignment does not reverse the order
i++;
}
dis.close(); // Close the input stream
In this version, music[] is array of SHORTS. So, the readShort() method would seem to make sense here, since the data is 16-bit PCM... However, on the Android that seems to be the problem. I changed that code to the following:
music=new byte[(int) file.length()];//size & length of the file
InputStream is = new FileInputStream (file);
BufferedInputStream bis = new BufferedInputStream (is, 8000);
DataInputStream dis = new DataInputStream (bis); // Create a DataInputStream to read the audio data from the saved file
int i = 0; // Read the file into the "music" array
while (dis.available() > 0)
{
music[i] = dis.readByte(); // This assignment does not reverse the order
i++;
}
dis.close(); // Close the input stream
In this version, music[] is an array of BYTES. I'm still telling the AudioTrack that it's 16-bit PCM data, and my Android doesn't seem to have a problem with writing an array of bytes into an AudioTrack thus configured... Anyway, it finally sounds right, so if anyone else wants to play Windows sounds on their Android, for some reason, that's the solution. Ah, Endianness......
R.
I found a lot of long answers to this question. My final solution, which given all the cutting and pasting is hardly mine, comes down to:
public boolean play() {
int i = 0;
byte[] music = null;
InputStream is = mContext.getResources().openRawResource(R.raw.noise);
at = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
minBufferSize, AudioTrack.MODE_STREAM);
try{
music = new byte[512];
at.play();
while((i = is.read(music)) != -1)
at.write(music, 0, i);
} catch (IOException e) {
e.printStackTrace();
}
at.stop();
at.release();
return STOPPED;
}
STOPPED is just a "true" sent back as a signal to reset the pause/play button.
And in the class initializer:
public Mp3Track(Context context) {
mContext = context;
minBufferSize = AudioTrack.getMinBufferSize(44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
}
Context is just "this" from the calling activity.
You can use a FileInputStream on the sdcard, etc. My files are in res/raw
Are you skipping the first 44 bytes of the file before you dump the rest of the file's data into the buffer? The first 44 bytes are the WAVE header and they would sound like random noise if you tried to play them.
Also, are you sure you are creating the AudioTrack with the same properties as the WAVE you are trying to play (sample rate, bit rate, number of channels, etc)? Windows actually does a good job of giving this information to you in the File Properties page:
As said by Aaron C, you have to skip initial 44 bytes or (as I prefer) read first 44 bytes that are the WAVE header. In this way you know how many channels, bits per sample, length, etc... the WAVE contains.
Here you can find a good implementation of a WAVE header parser/writer.
Please don't perpetuate terrible parsing code. WAV parsing is trivial to implement
http://soundfile.sapp.org/doc/WaveFormat/
and you will thank yourself by being able to parse things such as the sampling rate, bit depth, and number of channels.
Also x86 and ARM (at least by default) are both little endian , so native-endian WAV files should be fine without any shuffling.
Just confirm if you have AudioTrack.MODE_STREAM and not AudioTrack.MODE_STATIC in the AudioTrack constructor:
AudioTrack at = new AudioTrack(
AudioManager.STREAM_MUSIC,
sampleRate,
AudioFormat.CHANNEL_IN_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
// buffer length in bytes
outputBufferSize,
AudioTrack.MODE_STREAM
);
Sample wav file:
http://www.mauvecloud.net/sounds/pcm1644m.wav
Sample Code:
public class AudioTrackPlayer {
Context mContext;
int minBufferSize;
AudioTrack at;
boolean STOPPED;
public AudioTrackPlayer(Context context) {
Log.d("------","init");
mContext = context;
minBufferSize = AudioTrack.getMinBufferSize(44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
}
public boolean play() {
Log.d("------","play");
int i = 0;
byte[] music = null;
InputStream is = mContext.getResources().openRawResource(R.raw.pcm1644m);
at = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
minBufferSize, AudioTrack.MODE_STREAM);
try {
music = new byte[512];
at.play();
while ((i = is.read(music)) != -1)
at.write(music, 0, i);
} catch (IOException e) {
e.printStackTrace();
}
at.stop();
at.release();
return STOPPED;
}
}