marsha
marsha copied to clipboard
Shared media in a webinar
Feature Request
Is your feature request related to a problem or unsupported use case? Please describe.
During a Webinar, an instructor wants to share Media with student. The media can be a PDF or any office document. The instructor needs in a first time to upload these documents and once the convert process applied the document can be shared with students.
Backend spec
ShareLiveMedia
A new model must be created to manage this new resource. We can name it SharedLiveMedia, but this name is open to be changed. We will use this name in this issue for now.
ShareLiveMedia model contains following properties:
| SharedLiveMedia |
|---|
| id |
| video_id |
| upload_state |
| uploaded_on |
| nb_pages # This property contains the document's pages |
| extension |
| title |
| show_download |
Following API endpoints will be added
POST /api/sharedlivemedias/
GET /api/sharedlivemedias/ # Must be restricted to the current video context (present in the JWT Token)
GET /api/sharedlivemedias/{pk}/
POST /api/sharedlivemedias/initiate-upload/
The payload for a single resource will be
{
"id": "3d6a179c-cf18-47d5-9e8e-a1368a243c2d",
"video_id": "7cfb42e1-d53e-4a78-b39f-83277fa91a9b",
"active_stamp": "1638230400",
"filename": "python-expressions.pdf",
"is_ready_to_show": true,
"nb_pages": 3,
"show_download": true,
"title": "python expressions",
"upload_state": "ready",
"urls": {
"media": (
"https://abc.cloudfront.net/d9d7049c-5a3f-4070-a494-e6bf0bd8b9fb/"
"sharedlivemedias/7520c16b-5846-41ca-822b-52b446a96809/1638230400"
"/1638230400/1638230400.pdf?response-content-disposition="
"attachment%3B+filename%3Dpython-expressions.pdf&Expires="
"1638237600&Signature=A69S6ycsdBnPUNViT6moHzDz-Z~x-OczY6hU9pWqQ1wb"
"CFeZC06EmwA44aZ62EPeYJr~rBdraLSXJevyk99zPNGPuFinF0XK6ggWannUjrvfk"
"3Cqyt2ZGSI5QHwpKqo5crHj018SG28DNuA7cXsQ-BjlaSizwtmzJUV2Hcx5fvFDvx"
"FlSrp3lAHHSdOA~L7N2pn1sTfjgqXRjge7KnJGot-dZnlKAC3wCvuazbuLZmzdA7i"
"3rVdlNBIMCWhKE5WUUoXlW1tduPTqyqrzfOaoGv2TTsJJqPuEEWVwRRqv0DgRP27S"
"oL7qzIvG~OeNYrabMuRQoyFDbYpFRt~ZVQRSwA__"
"&Key-Pair-Id=cloudfront-access-key-id"
),
"pages": {
"1": (
"https://abc.cloudfront.net/d9d7049c-5a3f-4070-a494-e6bf0bd8b9"
"fb/sharedlivemedias/7520c16b-5846-41ca-822b-52b446a96809/1638"
"230400/1.png?Expires=1638237600&Signature=NMUCJsyMGlg1ZQ4ocHj"
"iqqHveeBcWEt9Hpd-QhSDsPco7iwTwfTS~tgQkjg0OfkZ16hPq118d8AZqXLk"
"cYvYR32Z5oDdV08P1LTh8ViUgBtz3XV8yxc~VmyQ3-OmFINSBqPXjZLf29bkX"
"ZaPg9LU~EditKJTaWrfhkpD2GljyXdj7X6uePqFWWVaIlkY4Xl1Dhjk04hjS2"
"f3m5hictwCCSgN-i8r~EKEeUkVCcdf3TGOFOCcrBlxd9525rzUtvgKMDqlyIK"
"GEwGAbK10iRI~pnB3EgXWxZ7U~8x-xZT7bmoIrt6NuVKvqf2mNLWWjizGAjOM"
"D1WpO1EGhhZBTdinNg__&Key-Pair-Id=cloudfront-access-key-id"
),
"2": (
"https://abc.cloudfront.net/d9d7049c-5a3f-4070-a494-e6bf0bd8b9"
"fb/sharedlivemedias/7520c16b-5846-41ca-822b-52b446a96809/1638"
"230400/2.png?Expires=1638237600&Signature=Qp3z9GZV5guZxb2jHuB"
"rbIsYMyKNJ7gMAKyycQusresKjhtwgOJD3hp~vW8b6B1oRRtp~Osb~T5j13Mb"
"S-XNCjICs3C~7b6p7e77CTg9V6TZF2rQZBz2oOoXiKGAWgkX8adxjFRAImE24"
"NVsudJtaKpef-4MPgFcSZfI3O9KQadCv4LW6Q~IZDCCl6JHHrDf6SSBggcyr8"
"sRcXM8dUTM2NWf56siMLk6UmY8BNra4qM9zlO7DDNPT1iGsuUcX2OIgHOVI0y"
"kH3PIvQ7yWqTCzKMJrP7xfNczWjHBNxrf~rtjbDV5fYO1gdUDlacfPpz4bnu0"
"1xPn9lUNr3uooIe~UA__&Key-Pair-Id=cloudfront-access-key-id"
),
"3": (
"https://abc.cloudfront.net/d9d7049c-5a3f-4070-a494-e6bf0bd8b9"
"fb/sharedlivemedias/7520c16b-5846-41ca-822b-52b446a96809/1638"
"230400/3.png?Expires=1638237600&Signature=G31rnBICbaateEwB8~a"
"FakNoZQMRE-Urzo-CRAvp~AYsdYNEFlbFgYfe-H6if34sT0TX1h2UpZe2HL8p"
"bWG0rIuBArYcpLcO9UPncXEBAKnX4WQr8Svl1s-ECBOE3WWC~-Em1o-93ss6q"
"YHgk3ABlxswysK5GmIGiraF1rjBNzktkZ87cbNAXpllRAl5swt~LAZyGH8bKn"
"S8reNawGJZo~ppAZEt1cHbpKkfzuoLTKHpuIgkxevzdZCVJ2pPnimAyKQGsYH"
"55aoLlD-BGcN~oFojDyDD00UUuq9HwRN1xZTYdS0881FSKNkL6Q7AfPkZ6bKP"
"POmevpdzePDS0Cj-PQ__&Key-Pair-Id=cloudfront-access-key-id"
),
},
},
}
The enpoint GET /api/sharedlivemedias/ will return a collection of sharedlivemedias. This same collection will be side loaded to the video payload.
Video
Video object must be modified to save the shared state. When an instructor start sharing, we must save the sharedlivemedias id shared and every time the page change, the current page must be saved.
These informations must be added to the video payload
Start/Stop and navigate in a Media
All the workflow should be managed by django. For this we have to create dedicated endpoints in the Video viewset or in the sharedlivemedias viewset, we have determine this point.
startendpoint set in the video object the activesharedlivemediasand the current page to 1. Then django broadcasts an XMPP message to all participants. The XMPP message contains in its body the video serialized in JSON.navigateendpoint changes the current page. This info must be save in the video object. Then django broadcasts an XMPP message to all participants. The XMPP message contains in its body the video serialized in JSON.endendpoint remove activesharedlivemediasin the video object. Then django broadcasts an XMPP message to all participants. The XMPP message contains in its body the video serialized in JSON.
A message broadcasted to all participant must be of type groupchat to the conference url. The event should be one of the 3 actions before and the body the video previously modified and saved.
The current active shared live media id and its current page should be save in the video model with two new fields nullable:
active_shared_live_media = models.ForeignKey(
"SharedLiveMedia",
blank=True,
null=True,
related_name="video",
verbose_name=_("Video"),
)
active_shared_live_media_page = models.PositiveIntegerField(
blank=True,
null=True,
help_text=_("Current displayed page of the active shared live media"),
)
This new fields should be added to the video serializer and a shared live media should not be deleted if currently active (also check if there is something to do on the on_delete action on the model)
Convert process
The goal of the convert process is to take a Media in input (PDF, office document, we have to determine a list of supported documents) and convert them in images. One image per document page.
To trigger the the convert process, we will use the already existing workflow we have with the lamda-encode function. The document is uploaded in the source bucket, the lambda-encode function is trigger. During this function the media is converted in image and the generated images are saved in the destination bucket. At the end, the Django application is fetched with the data needed to update the shared media object.
⚠ This process can be long and can consumes lot of resources. Lambda have some limitations (timeout, resources available, etc) and maybe triggering other lambdas or an other function in ECS can be needed.
⚠ lambda-encode is not a relevant name anymore. We can rename it in lambda-convert, but this must be done in a dedicated PR, before or after this issue is made.
Front spec
The front is responsible to display the current page when a sharedlivemedias is active.
A converse plug-in should be created to listen messages broadcasted in the XMPP conference room. When a message is received and validated (checking the type and the event) the video should be updated in the zustand store with the one received in the message.
Updating the store should rerender the component responsible to display the current page.
All the information needed to display the page are present in the video object.
Suggestion of tools for the convert process
Most of the library in python or javascript for node are layers on top of commands like soffice or ImageMagick or pdftoppm
The given strategy can be applied to convert a media file into multiple images:
Convert office files in PDF
The first step can be to convert every office files in a PDF. We can accept in input every files from microsoft office or (libre|open)office. We have to test this process with presentation files from Mac OS environment.
The soffice binary provided by libreoffice can be used to do this job. It can converts several input files format into PDF. We have to determine the input format to help him to do a better convert
Here is a details stackoverflow post explaining well hot to use it: https://stackoverflow.com/a/30465397
Convert PDF files in images
Once the media file converted in PDF, we have to convert to an image. Obviously if the original file is already a PDF, we begin directly at this step.
Several command line can be used here:
- pdftoppm (part of the poppler project and installed by the
poppler-utilspackage on ubuntu) - pdftocairo also part of poppler
- ImageMagick convert CLI
pdftoppm seems easier to use while ImageMagick convert allows to do more things.
For a better conversion from office files to pdf, the last version of libreoffice must be used.
@kernicPanel you can continue with Start/Stop and navigate in a Media part. I updated it.
All the workflow should be managed by django. For this we have to create dedicated endpoints in the Video viewset or in the sharedlivemedias viewset, we have determine this point.
I think /api/sharedlivemedias/{pk}/start/, for example, would be more intuitive than /api/video/{pk}/start as the "starting action" is more related to the SharedLiveMedia instance than the Video one.
Moreover, using the video viewset would force us to always specify the SharedLiveMedia id we want to act on by passing it in POST datas.
WDYT, @lunika ?
Ok you can use this endpoint.
I also think we should not allow starting a share while there is already an ongoing share. It's the front responsibility IMO to deal with it. They can stop the current to start the new one. Or ask the user what he wants to do (with a confirmation process), or other scenarios.
The django part of this project is done. We can keep open this issue for a record for the front application.