Please, help with audio record troubles

  • Replies:0
Yuriy Chekashkin
  • Forum posts: 1

Jun 2, 2015, 2:37:52 PM via Website

I writing audio from microphone to mp4 (aac audio). I get audio raw data from Microphone by AudioRecord and send to MediaCodec. After that I send the audio data to MediaMux to get a mp4 file. I have problem: then my application record audio in background service and user does something with device (to navigate in menu or use other application), result audio record have troubles (faster playback, pauses).

[enter link description here][1]

public void run() {
if (mIsInitialized) {
    switch (type) {
        case ENCODE_AUDIO_FRAME:
            if (!mStopReceived) {
                _offerAudioEncoder(mAudioData, presentationTimeNs);
                processAudioFrame();
            }
            break;
    }
    // prevent multiple execution of same task
    mIsInitialized = false;
    mEncodingServiceQueueLength -= 1;
} else {
    Log.e(TAG, "run() called but EncoderTask not initialized");
}

}

private void _offerAudioEncoder(byte[] input, long presentationTimeNs) {
if (audioBytesReceived == 0) {
    mAudioStartTime = presentationTimeNs;
}

mTotalInputAudioFrameCount++;
audioBytesReceived += input.length;
if (mEosSentToAudioEncoder && mStopReceived || input == null) {
    logStatistics();
    if (mEosReceived) {
        Log.d(TAG, "EOS received in offerAudioEncoder");
        closeAudioEncoder();
        mEosSentToAudioEncoder = true;
        if (!mStopReceived) {
            prepareAudioEncoder();
        } else {
            mEncodingService.shutdown();
        }
    }
    return;
}
// transfer previously encoded data to muxer
drainEncoder(mAudioEncoder, mAudioBufferInfo, mAudioTrackIndex, false, "audio");

try {
    ByteBuffer[] inputBuffers = mAudioEncoder.getInputBuffers();
    int inputBufferIndex = mAudioEncoder.dequeueInputBuffer(-1);
    if (inputBufferIndex >= 0) {
        ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
        inputBuffer.clear();
        inputBuffer.put(input);
        if (mAudioSoftwarePoller != null) {
            mAudioSoftwarePoller.recycleInputBuffer(input);
        }
        long presentationTimeUs = (presentationTimeNs - mAudioStartTime) / 1000; // in microseconds
        if (mEosReceived) {
            mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, input.length, presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
            closeAudioEncoder();
            mEosSentToAudioEncoder = true;
            if (mStopReceived) {
                mEncodingService.shutdown();
            }
        } else {
            mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, input.length, presentationTimeUs, 0);
        }
    }
} catch (Throwable t) {
    t.printStackTrace();
}

}

private void drainEncoder(MediaCodec encoder, MediaCodec.BufferInfo bufferInfo, TrackIndex trackIndex, boolean endOfStream, String type) {
int TIMEOUT_USEC = 100;
ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();
while (true) {
    int encoderStatus = encoder.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC);
    if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
        if (!endOfStream) {
            if (VERBOSE) Log.d(TAG, "INFO_TRY_AGAIN_LATER " + type + " out of while");
            break;      // out of while
        } else {
            if (VERBOSE) Log.d(TAG, "no " + type + " output available, spinning to await EOS");
        }
    } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
        // not expected for an encoder
        if (VERBOSE) Log.d(TAG, "INFO_OUTPUT_BUFFERS_CHANGED " + type);
        encoderOutputBuffers = encoder.getOutputBuffers();

    } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
        // should happen before receiving buffers, and should only happen once
        if (mMuxerStarted) {
            throw new RuntimeException("format changed after muxer start");
        }
        MediaFormat newFormat = encoder.getOutputFormat();
        Log.d(TAG, "encoder output format changed: " + newFormat + ".");

        // now that we have the Magic Goodies, start the muxer
        synchronized (mMuxer) {
            trackIndex.index = mMuxer.addTrack(newFormat);
            numTracksAdded++;
            Log.d(TAG, "Added " + type + " track index: " + trackIndex.index);
            if (numTracksAdded == TOTAL_NUM_TRACKS) {
                mMuxer.start();
                mMuxerStarted = true;
                Log.d(TAG, numTracksAdded + " tracks added. Muxer started");
                break;
            }
        }
    } else if (encoderStatus < 0) {
        Log.w(TAG, "unexpected result from " + type + " encoder.dequeueOutputBuffer: " +
                encoderStatus);
    } else {
        if (encodedData == null) {
            if (VERBOSE) Log.d(TAG, "drainEncoder(" + endOfStream + ") " + type + " encodedData == null");
            throw new RuntimeException("encoderOutputBuffer " + encoderStatus +
                    " was null");
        }
        if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
            // The codec config data was pulled out and fed to the muxer when we got
            // the INFO_OUTPUT_FORMAT_CHANGED status.  Ignore it.
            if (VERBOSE) Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
            bufferInfo.size = 0;
        }
        if (bufferInfo.size != 0) {
            if (!mMuxerStarted) {
                if (VERBOSE) Log.d(TAG, "drainEncoder(" + endOfStream + ") " + type + " Muxer not started");
                throw new RuntimeException("muxer hasn't started");
            }
            // adjust the ByteBuffer values to match BufferInfo (not needed?)
            encodedData.position(bufferInfo.offset);
            encodedData.limit(bufferInfo.offset + bufferInfo.size);
            synchronized (mMuxer) {
                mMuxer.writeSampleData(trackIndex.index, encodedData, bufferInfo);
            }
        }

        encoder.releaseOutputBuffer(encoderStatus, false);

        if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
            if (!endOfStream) {
                Log.w(TAG, "reached end of stream unexpectedly");
            } else {
                if (VERBOSE) Log.d(TAG, "end of stream reached");
            }
            break;
        }
    }
}
long endTime = System.nanoTime();

}

public void processAudioFrame() {
long audioPresentationTimeNs = System.nanoTime();
byte[] thisBuffer;
if (mDataBuffer.isEmpty()) {
    thisBuffer = new byte[mSamplesPerFrame];
} else {
    thisBuffer = mDataBuffer.poll();
}

mReadResult = mAudioRecorder.read(thisBuffer, 0, mSamplesPerFrame);
if (VERBOSE) Log.i(TAG, "FillBuffer       real: " + String.valueOf(mBufferWriteIndex)
        + " - " + String.valueOf(mBufferWriteIndex + mReadResult - 1));

if (mReadResult != AudioRecord.ERROR_BAD_VALUE && mReadResult != AudioRecord.ERROR_INVALID_OPERATION) {
    mBufferWriteIndex = mBufferWriteIndex + mReadResult - 1;
    mTotalFramesWritten++;
    if (mAudioEncoder != null) {
        mEncodingService.submit(new EncoderTask(Encoder.this, EncoderTaskType.ENCODE_AUDIO_FRAME));
    }


    if (!mIsRecording && mAudioRecorder != null) {
        mAudioRecorder.setRecordPositionUpdateListener(null);
        mAudioRecorder.release();
        mAudioRecorder = null;
        Log.i(TAG, "stopped");
    }
} else {
    Log.e(TAG, "Read error");
}

}

Reply