def add_or_update_medialive_output_group()

in source/controlplaneapi/runtime/app.py [0:0]


def add_or_update_medialive_output_group(name, program, profile, channel_id):
    print(
        f"Describing the MediaLive channel '{channel_id}' to get existing InputAttachments, Destinations, and EncoderSettings")

    try:
        response = medialive_client.describe_channel(
            ChannelId=channel_id
        )

        if response["State"] != "IDLE":
            raise BadRequestError(f"MediaLive channel '{channel_id}' is not in 'IDLE' state")

        last_known_medialive_config = response
        input_attachments = response["InputAttachments"]
        destinations = response["Destinations"]
        encoder_settings = response["EncoderSettings"]

        profile_table = ddb_resource.Table(PROFILE_TABLE_NAME)

        response = profile_table.get_item(
            Key={
                "Name": profile
            },
            ProjectionExpression="#Name, #ChunkSize",
            ExpressionAttributeNames={
                "#Name": "Name",
                "#ChunkSize": "ChunkSize"
            },
            ConsistentRead=True
        )

        if "Item" not in response:
            raise NotFoundError(f"Profile '{profile}' not found")

        chunk_size = response["Item"]["ChunkSize"]

        is_destination_create = True

        for index, destination in enumerate(destinations):
            if destination["Id"] == "awsmre":
                print(f"Updating the existing MRE destination present in the MediaLive channel '{channel_id}'")
                destinations[index]["Settings"][0][
                    "Url"] = f"s3ssl://{MEDIALIVE_S3_BUCKET}/{channel_id}/{program}/{name}/{profile}/{program}_{name}"
                is_destination_create = False
                break

        if is_destination_create:
            print(f"Creating a new destination for MRE in the MediaLive channel '{channel_id}'")

            mre_destination = {
                "Id": "awsmre",
                "Settings": [
                    {
                        "Url": f"s3ssl://{MEDIALIVE_S3_BUCKET}/{channel_id}/{program}/{name}/{profile}/{program}_{name}"
                    }
                ]
            }

            # Append MRE destination to the existing channel destinations
            destinations.append(mre_destination)

        audio_descriptions = encoder_settings["AudioDescriptions"] if "AudioDescriptions" in encoder_settings else []

        if not audio_descriptions:
            # At this time, MRE automatically picks the first input attached to the MediaLive channel 
            # to get the AudioSelectors information. In a future update, this input picking could be user driven
            audio_selectors = input_attachments[0]["InputSettings"]["AudioSelectors"] if "AudioSelectors" in \
                                                                                         input_attachments[0][
                                                                                             "InputSettings"] else []
            audio_selectors_name_list = [audio_selector["Name"] for audio_selector in audio_selectors]

            for audio_selector_name in audio_selectors_name_list:
                audio_descriptions.append(
                    {
                        "AudioSelectorName": audio_selector_name,
                        "AudioTypeControl": "FOLLOW_INPUT",
                        "LanguageCodeControl": "FOLLOW_INPUT",
                        "Name": f"audio_{uuid.uuid4().hex}"
                    }
                )

            # Include AudioDescriptions in the EncoderSettings
            encoder_settings["AudioDescriptions"] = audio_descriptions

        audio_description_name_list = [audio_description["Name"] for audio_description in audio_descriptions]

        output_groups = encoder_settings["OutputGroups"]
        is_new_output_group = True

        for index, output_group in enumerate(output_groups):
            if "HlsGroupSettings" in output_group["OutputGroupSettings"] and \
                    output_group["OutputGroupSettings"]["HlsGroupSettings"]["Destination"][
                        "DestinationRefId"] == "awsmre":
                print(f"Updating the existing OutputGroup for MRE in the MediaLive channel '{channel_id}'")

                output_groups[index]["OutputGroupSettings"]["HlsGroupSettings"]["SegmentLength"] = int(chunk_size)
                output_groups[index]["OutputGroupSettings"]["HlsGroupSettings"]["ProgramDateTimePeriod"] = int(
                    chunk_size)

                output_groups[index]["Outputs"][0]["AudioDescriptionNames"] = audio_description_name_list

                is_new_output_group = False
                break

        if is_new_output_group:
            mre_output_group = {
                "OutputGroupSettings": {
                    "HlsGroupSettings": {
                        "AdMarkers": [],
                        "CaptionLanguageMappings": [],
                        "CaptionLanguageSetting": "OMIT",
                        "ClientCache": "ENABLED",
                        "CodecSpecification": "RFC_4281",
                        "Destination": {
                            "DestinationRefId": "awsmre"
                        },
                        "DirectoryStructure": "SINGLE_DIRECTORY",
                        "DiscontinuityTags": "INSERT",
                        "HlsId3SegmentTagging": "DISABLED",
                        "IFrameOnlyPlaylists": "DISABLED",
                        "IncompleteSegmentBehavior": "AUTO",
                        "IndexNSegments": 10,
                        "InputLossAction": "PAUSE_OUTPUT",
                        "IvInManifest": "INCLUDE",
                        "IvSource": "FOLLOWS_SEGMENT_NUMBER",
                        "KeepSegments": 21,
                        "ManifestCompression": "NONE",
                        "ManifestDurationFormat": "FLOATING_POINT",
                        "Mode": "VOD",
                        "OutputSelection": "VARIANT_MANIFESTS_AND_SEGMENTS",
                        "ProgramDateTime": "INCLUDE",
                        "ProgramDateTimePeriod": int(chunk_size),
                        "RedundantManifest": "DISABLED",
                        "SegmentLength": int(chunk_size),
                        "SegmentationMode": "USE_SEGMENT_DURATION",
                        "SegmentsPerSubdirectory": 10000,
                        "StreamInfResolution": "INCLUDE",
                        "TimedMetadataId3Frame": "PRIV",
                        "TimedMetadataId3Period": 10,
                        "TsFileMode": "SEGMENTED_FILES"
                    }
                },
                "Outputs": [
                    {
                        "AudioDescriptionNames": audio_description_name_list,
                        "CaptionDescriptionNames": [],
                        "OutputName": "awsmre",
                        "OutputSettings": {
                            "HlsOutputSettings": {
                                "H265PackagingType": "HVC1",
                                "HlsSettings": {
                                    "StandardHlsSettings": {
                                        "AudioRenditionSets": "program_audio",
                                        "M3u8Settings": {
                                            "AudioFramesPerPes": 4,
                                            "AudioPids": "492-498",
                                            "NielsenId3Behavior": "NO_PASSTHROUGH",
                                            "PcrControl": "PCR_EVERY_PES_PACKET",
                                            "PmtPid": "480",
                                            "ProgramNum": 1,
                                            "Scte35Behavior": "NO_PASSTHROUGH",
                                            "Scte35Pid": "500",
                                            "TimedMetadataBehavior": "NO_PASSTHROUGH",
                                            "TimedMetadataPid": "502",
                                            "VideoPid": "481"
                                        }
                                    }
                                },
                                "NameModifier": "_1"
                            }
                        },
                        "VideoDescriptionName": "video_awsmre"
                    }
                ]
            }

            # Append MRE output group to the existing channel output groups
            output_groups.append(mre_output_group)

        encoder_settings["OutputGroups"] = output_groups

        video_descriptions = encoder_settings["VideoDescriptions"]
        is_new_video_description = True

        for index, video_description in enumerate(video_descriptions):
            if video_description["Name"] == "video_awsmre":
                print(
                    f"Skipping the addition of new video description for MRE as it already exists in the MediaLive channel '{channel_id}'")
                is_new_video_description = False
                break

        if is_new_video_description:
            mre_video_description = {
                "CodecSettings": {
                    "H264Settings": {
                        "AdaptiveQuantization": "AUTO",
                        "AfdSignaling": "NONE",
                        "Bitrate": 5000000,
                        "BufSize": 5000000,
                        "ColorMetadata": "INSERT",
                        "EntropyEncoding": "CABAC",
                        "FlickerAq": "ENABLED",
                        "ForceFieldPictures": "DISABLED",
                        "FramerateControl": "INITIALIZE_FROM_SOURCE",
                        "GopBReference": "DISABLED",
                        "GopClosedCadence": 1,
                        "GopNumBFrames": 2,
                        "GopSize": 1,
                        "GopSizeUnits": "SECONDS",
                        "Level": "H264_LEVEL_AUTO",
                        "LookAheadRateControl": "MEDIUM",
                        "MaxBitrate": 5000000,
                        "NumRefFrames": 1,
                        "ParControl": "INITIALIZE_FROM_SOURCE",
                        "Profile": "HIGH",
                        "QvbrQualityLevel": 8,
                        "RateControlMode": "QVBR",
                        "ScanType": "PROGRESSIVE",
                        "SceneChangeDetect": "DISABLED",
                        "SpatialAq": "ENABLED",
                        "SubgopLength": "FIXED",
                        "Syntax": "DEFAULT",
                        "TemporalAq": "ENABLED",
                        "TimecodeInsertion": "DISABLED"
                    }
                },
                "Name": "video_awsmre",
                "RespondToAfd": "NONE",
                "ScalingBehavior": "DEFAULT",
                "Sharpness": 50
            }

            # Append MRE video description to the existing channel video descriptions
            video_descriptions.append(mre_video_description)

        encoder_settings["VideoDescriptions"] = video_descriptions

        # Update the MediaLive channel with modified Destinations and EncoderSettings
        print(f"Updating the MediaLive channel '{channel_id}' with modified Destinations and EncoderSettings")
        medialive_client.update_channel(
            ChannelId=channel_id,
            Destinations=destinations,
            EncoderSettings=encoder_settings
        )

    except medialive_client.exceptions.NotFoundException as e:
        print(f"MediaLive channel '{channel_id}' not found")
        raise Exception(e)

    except Exception as e:
        print(
            f"Unable to add a new or update an existing OutputGroup for MRE in the MediaLive channel '{channel_id}': {str(e)}")
        raise Exception(e)

    else:
        return last_known_medialive_config