Recording a Live Stream
Once the LiveContribution
has been created, you are finally ready to stream.
Create the LiveRecorder
The audio and video live streaming is performed by a LiveRecorder
object in association with a LiveRecorderView
interface to implement.
The LiveRecorder
needs to be instantiated only once, so you need to use it as a singleton while the view will follow the Android life cycle.
Here's how to create the LiveRecorder
:
LiveRecorder liveRecorder = new LiveRecorder(liveContribution);
Activity life cycle
Since you'll use an Activity
or a Fragment
as a LiveRecorderView
, you may want to avoid your view to be re-created while streaming. We recommand that the activity used as LiveRecorderView
supports only 1 orientation and avoid changing it during streaming.
In any case, you should ALWAYS use the LiveRecorder as a singleton and avoid re-creating it if your Activity is destroyed and re-created.
Implement the LiveRecorderView
To be able to use the LiveRecorder
you need to implement the LiveRecorderView
.
We recommand using an AspectFrameLayout
(available in the Live SDK) as a container for the camera preview since it will automaticaly adopt the right aspect depending on the camera.
Here's a basic sample of a layout (activity_live.xml
) with the camera preview container for an activity:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
<com.newzulu.livesdk.AspectFrameLayout
android:id="@+id/live_preview_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
And here's how the implementation is done:
public class LiveActivity extends AppCompatActivity implements LiveRecorderView
{
private AspectFrameLayout mPreviewContainer;
// This singleton implementation is up to you
@NonNull
private final LiveRecorder mLiveRecorder = getLiveRecorderInstance();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live);
mPreviewContainer = (AspectFrameLayout) findViewById(R.id.live_preview_container);
}
@Override
protected void onStart()
{
super.onStart();
mLiveRecorder.onStart(this);
}
@Override
protected void onResume()
{
super.onResume();
mLiveRecorder.onResume(this);
}
@Override
protected void onPause()
{
mLiveRecorder.onPause(this);
super.onPause();
}
@Override
protected void onStop()
{
mLiveRecorder.onStop(this);
super.onStop();
}
@NonNull
@Override
public Context getContext()
{
return this;
}
@NonNull
@Override
public ViewGroup getPreviewContainer()
{
return mPreviewContainer;
}
@Override
public boolean isViewChangingConfigurations()
{
return isChangingConfigurations();
}
@Override
public boolean hasPermission(@NonNull String permission)
{
return ContextCompat.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
}
@Override
public void onPreviewRatioChanged(double ratio)
{
mPreviewContainer.setAspectRatio(ratio);
}
@Override
public void onLiveRecorderError(final LiveException e)
{
// An error occurred with the live recorder.
}
@Override
public void onRecordingStatusChange(boolean isStarted)
{
// The recording has started or stopped.
}
}
Recording
When the user taps the record button, you invoke the startRecording()
method and when the user taps the record button again, you invoke the stopRecording()
method.
Here's a way to do it:
mRecordButton = (Button) findViewById(R.id.record_button);
mRecordButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
if (mLiveRecorder != null)
{
if (mLiveRecorder.isRecording())
{
mLiveRecorder.stopRecording();
}
else
{
mLiveRecorder.startRecording();
}
}
}
});
Note the use of the
isRecording()
method to check if theLiveRecorder
is not already recording a stream.
Stopping the recording could takes some time as the recorder needs to send all pending audio and video to the Newzulu Live streaming server before completing. You should wait until receiving a callback indicating the record has stopped.
You may stop and restart the recording as many times as you want.
Responding to events
In a normal workflow the actions are asynchronous and errors may arise, so callbacks are provided by the LiveRecorderView
implementation.
Note: those callbacks are called from a worker thread so if you perform an action on a UI object an error will arise from the linter.
Here's an example for an activity:
@Override
public void onRecordingStatusChange(boolean isStarted)
{
if (isStarted)
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
mRecordButton.setText("Stop recording");
}
});
}
else
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
mRecordButton.setText("Start recording");
}
});
}
}
Handling errors
An error may arise and unexpectedly interrupt the recording, they will rise via onLiveRecorderError(LiveException e)
, a cause can help for troubleshooting but it usualy means a blocking error has been encountered.
@Override
public void onLiveRecorderError(final LiveException e)
{
// An error occured with the live recorder.
}
The error has a Type
property that can be one of the following cases:
NETWORK
: A network error occurred and the SDK was unable to reach the remote server.SERVICE_ERROR
: The remote server encountered an error, you should try again later.MISSING_PERMISSION
: A mandatory permission is missing.HARDWARE
: An hardware error occurred using the camera or the microphone.UNKNOWN
: An unknown internal error occurred.
Extras
The LiveRecorder
comes with a few helper methods to manage the camera:
setTorchOn(boolean torchOn)
- to start/stop the torch if available on the device with the selected camera.toggleCamera()
- to toggle back/front camera if available.focus()
- to force manual focus (should not be necessary).
Finish your contribution
Once you're done recording, you need to finish the Live Contribution.