hi
i have audio recording in my i use mediarecorder class for recding audio but i have out of memory exception when i reach 2 m , that my limit. i given my code below.
time
private static void audiorecding()
{
if (audio_recding_stop_flag == 0) {
audio_recding_stop_flag = 1;
recorder.stop();
recorder.reset();
recorder.release();
recorder=new MediaRecorder();
int maxtime = audio_seekbar_play_indication.getMax();
audio_seekbar_progress = 0;
audio_seekbar_incr = maxtime/ AngiesData.gettotalaudiorecdingtimeinseconds(audio_recding_time.getText().toString());
audio_recding_time.stop();
recd_stop_audio.setBackgroundResource(R.drawable.rec_btn);
audio_play_pause.setEnabled(true);
delete_recding.setEnabled(true);
AngiesData.angiesListContext.setAudioRecd(true);
AngiesData.angiesListContext.setAudioRecdingTime((String) audio_recding_time.getText());
}
else {
audio_recding_stop_flag = 0;
try {
audio_play_pause.setEnabled(false);
delete_recding.setEnabled(false);
recd_stop_audio.setBackgroundResource(R.drawable.recording_stop);
audio_recding_time .setBase(SystemClock.elapsedRealtime());
audio_recding_time.start();
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC); // AudioSource
recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); // OutputFormat
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
path = InitialValueLoader.sanitizePath("Audio/VoiceReport");
InitialValueLoader.filecheck(path);
recorder.setOutputFile(path);
recorder.setMaxDuration(120000);
recorder.prepare();
recorder.start();
} catch (Exception e) {
e.printStackTrace();
}
}
I would try something with the AudioRecord-Class ( http://developer.android.com/reference/android/media/AudioRecord.html), use the read()-function with a while-loop and keep going until you got your 2 min. of samples (check the sampleRate, e.g. 44.1 Khz => 44100 smpls/sec => 60*44100 smpl/min). Making sure you have 2 min. of audio with the help of a timer is not a good idea. With timers you can never be sure on the precision, if another thread is interferring your timer will be evoked later, and in audio samples speaking it might be MUCH later.
I suggest useing a Chronometer instead of a timer
In programming if you have to deal with timings generally all time values are in milliseconds. You are trying to stop the recording after two seconds there not two minutes which would be 120000 milliseconds.
Related
I made an audio recorder using MediaRecorder and saving the file as a m4a, like this:
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
recorder.setAudioEncodingBitRate(128000);
recorder.setAudioSamplingRate(44100);
recorder.setOutputFile(AveActivity.REC_DIR + "/" + song);
Very simple, works great.
Now I want to implement gain into this (i.e., to make the volume considerably greater), since the audio is too low: I want my recorder to record birds and wildlife, and being wild means it is almost always far away....
So, I migrated my code to use AudioRecord based on this thread. The problem is that with this I get PCM audio, which is a pain to convert to WAV (I did that too). I did that first saving the PCM, then converting to WAV... And, yet, the WAV files are 6 times bigger than the m4a.
First question: Is there any way to apply gain before saving the file using MediaRecorder??
Second question: Is there an easy way to encode the PCM audio directly to m4a "on the fly", without saving PCM and re-encoding? I mean, I get the PCM using a read command like this:
recorder.startRecording();
recordingThread = new Thread(this::writeAudioDataToFile, "AudioRecorder Thread");
recordingThread.start();
...
private void writeAudioDataToFile() {
....
while (recorder != null) {
int numRead = recorder.read(sData, 0, bufferSize);
// **Here is the gain! Hardcoded for now...**
int gain = 8;
if (numRead > 0)
for (int i = 0; i < numRead; ++i)
sData[i] = (short) Math.max(Math.min(sData[i] * gain, Short.MAX_VALUE), Short.MIN_VALUE);
try {
os.write(short2byte(sData), 0, 2*bufferSize);
} catch (IOException e) {
e.printStackTrace();
}
}
....
}
I’m trying to build a music analytics app for android platform.
the app is using MediaRecorder.AudioSource.MIC
to record the music form the MIC and them encode it PCM 16BIT with 11025 freq, but the recorded audio sample are very low quality is there any way to make it better, decrease the noise?
mRecordInstance = new AudioRecord(MediaRecorder.AudioSource.MIC,FREQUENCY, CHANNEL,ENCODING, minBufferSize);
mRecordInstance.startRecording();
do
{
samplesIn += mRecordInstance.read(audioData, samplesIn, bufferSize - samplesIn);
if(mRecordInstance.getRecordingState() == AudioRecord.RECORDSTATE_STOPPED)
break;
}
while (samplesIn < bufferSize);
Thanks in Advance
The solution above didnt work for me.
So, i searched around and found this article.
Long story short, I used MediaRecorder.AudioSource.VOICE_RECOGNITION instead of AudioSource.MIC, which gave me really good results and noise in the background did reduce very much.
The great thing about this solution is, it can be used with both AudioRecord and MediaRecorder class.
The best combination of SR and buffer size is very device dependant, so your results will vary depending on the hardware. I use this utility to figure out what the best combination is for devices running Android 4.2 and above;
public static DeviceValues getDeviceValues(Context context) {
try {
AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
try {
Method getProperty = AudioManager.class.getMethod("getProperty", String.class);
Field bufferSizeField = AudioManager.class.getField("PROPERTY_OUTPUT_FRAMES_PER_BUFFER");
Field sampleRateField = AudioManager.class.getField("PROPERTY_OUTPUT_SAMPLE_RATE");
int bufferSize = Integer.valueOf((String)getProperty.invoke(am, (String)bufferSizeField.get(am)));
int sampleRate = Integer.valueOf((String)getProperty.invoke(am, (String)sampleRateField.get(am)));
return new DeviceValues(sampleRate, bufferSize);
} catch(NoSuchMethodException e) {
return selectBestValue(getValidSampleRates(context));
}
} catch(Exception e) {
return new DeviceValues(DEFAULT_SAMPLE_RATE, DEFAULT_BUFFER_SIZE);
}
}
This uses reflection to check if the getProperty method is available, because this method was introduced in API level 17. If you are developing for a specific device type, you might want to experiment with various buffer sizes and sample rates. The defaults that I use as a fallback are;
private static final int DEFAULT_SAMPLE_RATE = 22050;
private static final int DEFAULT_BUFFER_SIZE = 1024;
Additionally I check the various SR by seeing if getMinBufferSize returns a reasonable value for use;
private static List<DeviceValues> getValidSampleRates(Context context) {
List<DeviceValues> available = new ArrayList<DeviceValues>();
for (int rate : new int[] {8000, 11025, 16000, 22050, 32000, 44100, 48000, 96000}) { // add the rates you wish to check against
int bufferSize = AudioRecord.getMinBufferSize(rate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
if (bufferSize > 0 && bufferSize < 2048) {
available.add(new DeviceValues(rate, bufferSize * 2));
}
}
return available;
}
This depends on the logic that if getMinBufferSize returns 0, the sample rate is not available in the device. You should experiment with these values for your particular use case.
Though it is an old question following solution will be helpful.
We can use MediaRecorder to record audio with ease.
private void startRecording() {
MediaRecorder recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
recorder.setAudioEncodingBitRate(96000)
recorder.setAudioSamplingRate(44100)
recorder.setOutputFile(".../audioName.m4a");
try {
recorder.prepare();
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
recorder.start();
}
Note:
MediaRecorder.AudioEncoder.AAC is used as MediaRecorder.AudioEncoder.AMR_NB encoding is no longer supported in iOS. Reference
AudioEncodingBitRate should be used either 96000 or 128000 as required for clarity of sound.
I am trying to record and process audio data based on differences in what gets recorded in the left and right channel. For this I am using Audio Record class, with MIC as input and STEREO mode.
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate,
AudioFormat.CHANNEL_IN_STEREO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize);
My issue is that I get exactly the same data in both the channels. (alternate samples are separated to get individual channel inputs). Please help. I am not sure why this is happening.
Using this configuration:
private int audioSource = MediaRecorder.AudioSource.MIC;
private static int sampleRateInHz = 48000;
private static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
The data in the audio data is as follows.
leftChannel data: [0,1],[4,5]...
rightChannel data: [2,3],[6,7]...
So you need to seperate the data.
readSize = audioRecord.read(audioShortData, 0, bufferSizeInBytes);
for(int i = 0; i < readSize/2; i = i + 2)
{
leftChannelAudioData[i] = audiodata[2*i];
leftChannelAudioData[i+1] = audiodata[2*i+1];
rightChannelAudioData[i] = audiodata[2*i+2];
rightChannelAudioData[i+1] = audiodata[2*i+3];
}
Hope this helpful.
Here is a working example for capturing audio in stereo (tested with Samsung Galaxy S3 4.4.2 SlimKat):
private void startRecording() {
String filename = Environment.getExternalStorageDirectory().getPath()+"/SoundRecords/"+System.currentTimeMillis()+".aac";
File record = new File(filename);
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
recorder.setAudioEncodingBitRate(128000);
recorder.setAudioSamplingRate(96000);
recorder.setAudioChannels(2);
recorder.setOutputFile(filename);
t_filename.setText(record.getName());
try {
recorder.prepare();
recorder.start();
} catch (IOException e) {
e.printStackTrace();
}
}
If your phone supports stereo capturing, then this should work :)
You cannot obtain a stereo input in this way on your device.
Although the Nexus 4 has two microphones, they are not intended for stereo recording, but instead are likely for background noise cancellation.
See https://groups.google.com/forum/#!topic/android-platform/SptXI964eEI where various low-level modifications of the audio system are discussed in an attempt to accomplish stereo recording.
hello,i want to use mediaRecorder to record voice. i want to save the format is amr.
this.mediaRecorder = new MediaRecorder();
this.mediaRecorder.setAudioChannels(1);
this.mediaRecorder.setAudioSamplingRate(8000);
this.mediaRecorder.setAudioEncodingBitRate(16);
this.mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
this.mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
this.mediaRecorder.setOutputFile(this.file.getAbsolutePath());
this.mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
i used this.mediaRecorder.setAudioEncodingBitRate(16), some device is ok
mediaRecorder.setAudioEncodingBitRate(12500),somedevice is ok
but i delete the mediaRecorder.setAudioEncodingBitRate some device is ok
so my question how to get the default the AudioEncodingBitRate.
which parameter i need to use?
You set the AudioEncodingBitRate too low. I made the same mistake :-)
This seems to work:
MediaRecorder recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
if (Build.VERSION.SDK_INT >= 10) {
recorder.setAudioSamplingRate(44100);
recorder.setAudioEncodingBitRate(96000);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
} else {
// older version of Android, use crappy sounding voice codec
recorder.setAudioSamplingRate(8000);
recorder.setAudioEncodingBitRate(12200);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
}
recorder.setOutputFile(file.getAbsolutePath());
try {
recorder.prepare();
} catch (IOException e) {
throw new RuntimeException(e);
}
The idea comes from here
plus: read the docs. The docs of setAudioSamplingRate say the following:
The sampling rate really depends on the format for the audio recording, as well as the capabilities of the platform. For instance, the sampling rate supported by AAC audio coding standard ranges from 8 to 96 kHz, the sampling rate supported by AMRNB is 8kHz, and the sampling rate supported by AMRWB is 16kHz.
I am using bellow configurations and gives amazing clear recording output.
localFileName = getFileName()+".wav";
localFile = new File(localdir, localFileName);
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
mRecorder.setOutputFormat(AudioFormat.ENCODING_PCM_16BIT);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mRecorder.setAudioChannels(1);
mRecorder.setAudioEncodingBitRate(128000);
mRecorder.setAudioSamplingRate(44100);
mRecorder.setOutputFile(localFile.getPath());
however if you are recording along with playing audio simultaneously it has some issues in samsung devices.
[but again only when you are playing audio and recording both together at the same time]
I find that the encoding bitrate should be calculated from the sample rate.
There is a good write-up of how these values relate on https://micropyramid.com/blog/understanding-audio-quality-bit-rate-sample-rate/
I use 8:1 compression for high-quality recordings. I prefer 48 KHz sampling, but the same logic works at an 8000 Hz sample rate requested for this post.
final int BITS_PER_SAMPLE = 16; // 16-bit data
final int NUMBER_CHANNELS = 1; // Mono
final int COMPRESSION_AMOUNT = 8; // Compress the audio at 8:1
public MediaRecorder setupRecorder(String filename, int selectedAudioSource, int sampleRate) {
final int uncompressedBitRate = sampleRate * BITS_PER_SAMPLE * NUMBER_CHANNELS;
final int encodedBitRate = uncompressedBitRate / COMPRESSION_AMOUNT;
mediaRecorder = new MediaRecorder();
try {
mediaRecorder.setAudioSource(selectedAudioSource);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
mediaRecorder.setAudioSamplingRate(sampleRate);
mediaRecorder.setAudioEncodingBitRate(encodedBitRate);
mediaRecorder.setOutputFile(filename);
}catch (Exception e) {
// TODO
}
return mediaRecorder;
}
MediaRecorder mediaRecorder = setupRecorder(this.file.getAbsolutePath(),
MediaRecorder.AudioSource.MIC,
8000);
I am writing an app that basically just tests if we can get anything at all from the microphone.
It works perfectly on several android devices, but not on the LG Optimus. Everytime I call MediaRecorder.getMaxAmplitude on the LG it returns 0.
The device is successfully recording, because I can listen to the recordings.
getMaxAmplitude returns the maximum amplitude since the last time you called it.
So, the first time you call it, it initializes itself (and so returns 0) the second time, it should return another value. According to the documentation :
getMaxAmplitude() returns the maximum absolute amplitude that was sampled since the last call to this method. Call this only after the setAudioSource().
Returns the maximum absolute amplitude measured since the last call, or 0 when called for the first time
Or, if you use it right, you have the same problem as I have. My code works on a galaxyTab 7(Froyo), but not 10.1 (Honeycomb).
EDIT : I repaired my problem (I hope it'll help you too). Make sure the first time you call getMaxAmplitude, in order to initialize it, you called start() first.
I used:
recorder.prepare();
recorder.getMaxAmplitude();
recorder.start();
//listening to the user
int amplitude = recorder.getMaxAmplitude();
When it should have been :
recorder.prepare();
recorder.start();
recorder.getMaxAmplitude();
//listening to the user
int amplitude = recorder.getMaxAmplitude();
EDIT : This code still has flaws it seems. This code doesn't seems to work on S2, for instance. It'll return 0. But I call getMaxAmplitude() only twice, so if you need to update the amplitude every second for example, it may be ok.
A solution is to have the amplitude reading inside of a thread. You will see that from time to time you will have a value different than 0.0f.
private Runnable mPollTask = new Runnable() {
public void run() {
while(true){
double amp = mSensor.getAmplitude();
System.out.print("Amplitude: ");
System.out.println(amp);
}
}
};
Below code worked for me, need to set setAudioSamplingRate and setAudioEncodingBitRate
MediaRecorder recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
if (Build.VERSION.SDK_INT >= 10) {
recorder.setAudioSamplingRate(44100);
recorder.setAudioEncodingBitRate(96000);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
} else {
// older version of Android, use crappy sounding voice codec
recorder.setAudioSamplingRate(8000);
recorder.setAudioEncodingBitRate(12200);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
}
recorder.setOutputFile(file.getAbsolutePath());
try {
recorder.prepare();
} catch (IOException e) {
throw new RuntimeException(e);
}