How we used Mux on our react native app

Jim Stefanakis
6 min readMar 3, 2021

--

Troosh is our latest venture, a mentoring app to help people learn new skills affordably. A place where you can monetize your knowledge regardless of your experience level.

An interactive app where a multitude of media are used to provide the best experience for both mentors and mentees. Videos and (soon) streaming are a crucial part of the app experience.

After experiencing the hassle free workflow of stripe I tried to look for something similar for our video services and then I found Mux!

I found several recourses on how to implement live streaming for Mux, but I couldn’t find anything specifically for uploading videos, so I had to improvise, adapt and overcome. Here is the final result of our implementation. The tech stack that will be used in this article is react native and django. This article continues assuming you know the basics for the above stack.

Setting up our backend endpoints for video uploads

Step 1

First we need to install the Mux library for python (or your language of choice) following the instructions here https://mux.com/for/python/. The following code will be added in the views.py where our django API app lives. After installing Mux for python we import it into our code.

import mux_python

Step 2

Then we need to create a Direct Upload endpoint for our video which we will use to perform the upload. Basically Mux will give us a one-time use url that we will then use to upload the video to.

First we create an api view on our backend that we will POST and will give us the Mux url back.

@api_view(http_method_names=['POST'])
@permission_classes((permissions.IsAuthenticated,))
def get_video_url(request):
pass

Then we need to add attach the token id and token secret to our python Mux configuration.

@api_view(http_method_names=['POST'])
@permission_classes((permissions.IsAuthenticated,))
def get_video_url(request):

#Authentication Setup
configuration = mux_python.Configuration()
configuration.username = os.environ['MUX_TOKEN_ID']
configuration.password = os.environ['MUX_TOKEN_SECRET']

Step 3

Our end goal was to upload a video to Mux and have the video data saved in one of our django models. In our case we got two models. One is Post and the other is Video. Since our posts can contain multiple videos we create a foreign key on the videos model pointing to the posts model.

The endpoint we are currently creating only gives us the url from Mux we will use to upload the video. After this request our servers job is done, and we are waiting for Mux to receive the video, process it and give us the information back.

The problem is when we receive the data from Mux we will not know which post the video is supposed to be attached to, so we need to give extra information to Mux before which we will then use to identify where the video belongs.

To handle this we had to modify our code a bit.

@api_view(http_method_names=['POST'])
@permission_classes((permissions.IsAuthenticated,))
def get_video_url(request):

#Authentication Setup
configuration = mux_python.Configuration()
configuration.username = os.environ['MUX_TOKEN_ID']
configuration.password = os.environ['MUX_TOKEN_SECRET']
passthrough_id = str(uuid.uuid1())

# Mark post as processing while video is being processed by mux
post = Post.objects.get(id=request.data['post'])
post.status == Post.PROCESSING
post.save()
PostVideoAssetMetaData.objects.
create(passthrough=passthrough_id, post=post)
create_asset_request = mux_python.CreateAssetRequest(
playback_policy=[mux_python.PlaybackPolicy.PUBLIC],
mp4_support="standard", passthrough=passthrough_id)

A lot of changes happened above, let’s break it down. First we created a passthrough_id variable which will be our identifier that we will use when we get the information back to find the post that this video is attached to.

In our use case we want to notify the user that the post is going through processing while Mux does its stuff, so we mark it as PROCESSING.

Then we use an intermediary model PostVideoAssetMetaData which contains both the passthrough identifier and the post it is attached to.

Step 4

Now the setup is done and all there is left to do is request the upload url from Mux.

@api_view(http_method_names=['POST'])
@permission_classes((permissions.IsAuthenticated,))
def get_video_url(request):

#Authentication Setup
configuration = mux_python.Configuration()
configuration.username = os.environ['MUX_TOKEN_ID']
configuration.password = os.environ['MUX_TOKEN_SECRET']
passthrough_id = str(uuid.uuid1())

# Mark post as processing while video is being processed by mux
post = Post.objects.get(id=request.data['post'])
post.status == Post.PROCESSING
post.save()
PostVideoAssetMetaData.objects.
create(passthrough=passthrough_id, post=post)
create_asset_request = mux_python.CreateAssetRequest(
playback_policy=[mux_python.PlaybackPolicy.PUBLIC],
mp4_support="standard", passthrough=passthrough_id)
# API Client Initialization
request = mux_python.CreateUploadRequest
(new_asset_settings=create_asset_request, test=True)
direct_uploads_api = mux_python.DirectUploadsApi
(mux_python.ApiClient(configuration))
response = direct_uploads_api.create_direct_upload(request) try:
pass
except ApiException as e:
print("Exception when \
calling AssetsApi->list_assets: %s\n" % e)
return Response({"url": response.data.url})

Lots of stuff happened again.

First we create a create_asset_request variable with our passthrough attached to it. You can see the passthrough variable as well as some other variables in the docs here https://docs.mux.com/reference#assets.

Then we create a direct_uploads_api instance with the configurations we set up above in order to create the upload url.

Finally, we request the direct upload url and store the Mux response then return it from our view to react native.

Our backend is not fully completed yet, but we can take a break for now and head over to our react native implementation.

Uploading the video from react native

Since react native has kind of its own way to upload media we had to do some digging in order to figure out how to handle the video upload to Mux.

Turns out the secret sauce is this file upload library here https://github.com/joltup/rn-fetch-blob.

Step 1

Install the RNFetchBlob library using npm (or yarn).

npm install --save rn-fetch-blob

Step 2

For simplicity, I won’t get into detail on how to select a video from the gallery (we are using this library https://github.com/ivpusic/react-native-image-crop-picker)

Let’s also assume we have a state like this

const [video, setVideo] = useState(null);

Step 3

We need to create a function that first, requests the Mux upload url from our API and then uses that url to upload the video to Mux

async function handleUploadVideo(post){
const data = RNFetchBlob.wrap(video.path);
const formData = new FormData();
formData.append('post', post.id);

const url = `${Config.API_URL}/v1/upload_video/`;
const response = await axios.post(url);
const uploadUrl = response.data.url;
await RNFetchBlob.fetch(
'PUT',
uploadUrl,
null,
data
)
}

This is a rough draft of what we did above

  1. Used RNFetchBlob here to create an uploadable instance of our video file.
  2. Attached the post id to our request.
  3. Created a POST request to the endpoint (`${Config.API_URL}/v1/upload_video/`) we created in the beginning.
  4. Got the upload url from the above request.
  5. Used the upload url to upload our video.

Receiving the video after Mux is done

Mux uses webhooks to notify us when the uploading / processing is done. This was the final step to completing the video upload integration.

Step 1

After setting up the webhook on the Mux platform we had to create an API view on our backend that will receive the webhook. This webhook contains some extra data we need, specifically the playback_ids which are the urls Mux saves the video at. We are using these later to display the video on our app.

@api_view(http_method_names=['POST'])
@permission_classes((permissions.AllowAny,))
def upload_video_webhook(request):
if request.data['type'] == 'video.asset.ready':
passthrough = request.data['data']['passthrough']
playback_ids = request.data['data']['playback_ids']
asset_id = request.data['data']['id']
video_data = PostVideoAssetMetaData.objects.get
(passthrough=passthrough)
video = Video.objects.create(asset_id=asset_id,
passthrough=video_data.passthrough,
post=video_data.post)
for playback_id in playback_ids:
PlaybackId.objects.create
(playback_id=playback_id['id'],
policy=playback_id['policy'], video=video)
video_data.post.status = Post.DONE
video_data.post.save()
return Response()

Lots of code here let’s break it down.

  1. We get the passthrough, playback_ids and asset_id from the request Mux sent back.
  2. Find the PostVideoAssetMetaData object with the passthrough so we can find the post it belongs to.
  3. Create a video instance with the playback_ids we got from Mux
  4. We use another model (PlaybackId) to store the playback_ids.
  5. Finally, we mark the post status as DONE so the user can now see that his / her video has been processed by our servers and is now available for everyone!

Only one thing is missing and that is to verify that the request is actually coming from Mux, but we will not cover this now to keep things simple.

Conclusion

With that Troosh is now ready to handle videos with the Mux platform. The implementation was quite simple and the docs were easy to read.

Look forward for more of our implementations and more behind the scenes info on how we build Troosh!

--

--

Jim Stefanakis

Entrepreneur in the tech industry 💻 | 10+ failed products | 1 successful startup development studio | Living in Greece 🇬🇷