andreasperelli andreasperelli - 5 months ago 163
Android Question

MediaRecorder issue on Android Lollipop

I'm testing libstreaming on new Android Lollipop, and this code that worked on previous release, seems to launch exception.

try {
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setCamera(mCamera);

mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mMediaRecorder.setVideoEncoder(mVideoEncoder);
mMediaRecorder.setPreviewDisplay(mSurfaceView.getHolder().getSurface());
mMediaRecorder.setVideoSize(mRequestedQuality.resX,mRequestedQuality.resY);


mMediaRecorder.setVideoFrameRate(mRequestedQuality.framerate);

// The bandwidth actually consumed is often above what was requested

mMediaRecorder.setVideoEncodingBitRate((int)(mRequestedQuality.bitrate*0.8));

// We write the ouput of the camera in a local socket instead of a file !
// This one little trick makes streaming feasible quiet simply: data from the camera
// can then be manipulated at the other end of the socket

mMediaRecorder.setOutputFile(mSender.getFileDescriptor());

mMediaRecorder.prepare();
mMediaRecorder.start();

} catch (Exception e) {
throw new ConfNotSupportedException(e.getMessage());
}


Launched exception is:

MediaRecorder: start failed -38

11-18 09:50:21.028: W/System.err(15783): net.majorkernelpanic.streaming.exceptions.ConfNotSupportedException
11-18 09:50:21.028: W/System.err(15783): at net.majorkernelpanic.streaming.video.VideoStream.encodeWithMediaRecorder(VideoStream.java:442)
11-18 09:50:21.028: W/System.err(15783): at net.majorkernelpanic.streaming.MediaStream.start(MediaStream.java:250)

I've tried to comment:

mMediaRecorder.setOutputFile(mSender.getFileDescriptor());

no exception launched, but when I start streaming a dialog tell me that need an outputfile.

Help appreciated.

Answer

I filed a bug report on AOSP. https://code.google.com/p/android/issues/detail?id=80715

"The current SELinux policies don't allow for mediaserver to handle app generated abstract unix domain sockets.

Instead, I'd recommend you create a pipe-pair ( http://developer.android.com/reference/android/os/ParcelFileDescriptor.html#createPipe() ) which is allowed by the Android 5.0 policy. " I don't know why they did this or how we were supposed to know.

I'm using a very old/modified (can't tell) version of libstreaming where mediastream is still extended from mediarecorder, but looking at the current version, in MediaStream you'll probably want to change createSockets to something including the following:

        ParcelFileDescriptor[] parcelFileDescriptors =ParcelFileDescriptor.createPipe();
        parcelRead = new ParcelFileDescriptor(parcelFileDescriptors[0]);
        parcelWrite  = new ParcelFileDescriptor(parcelFileDescriptors[1]);

then in your video/audio stream

setOutputFile(parcelWrite.getFileDescriptor());

and in that same file change

    // The packetizer encapsulates the bit stream in an RTP stream and send it over the network
    mPacketizer.setInputStream(mReceiver.getInputStream());
    mPacketizer.start();

to

            InputStream is = null;
            try{ is = new ParcelFileDescriptor.AutoCloseInputStream(parcelRead);
            }
            catch (Exception e){}
            mPacketizer.setInputStream(is);

As andreasperelli pointed out in the comment, make sure to close the ParcelFileDescriptors in closeSockets(), or depending on your implementation and version, before closeSockets() and before you call MediaRecorder.stop().

Comments