GinoPane/PHPolyglot

View on GitHub
src/API/Implementation/TTS/IbmWatson/AudioFormat/IbmWatsonAudioFormatsTrait.php

Summary

Maintainability
A
25 mins
Test Coverage
<?php

namespace GinoPane\PHPolyglot\API\Implementation\TTS\IbmWatson\AudioFormat;

use GinoPane\NanoRest\Supplemental\Headers;
use GinoPane\PHPolyglot\API\Supplemental\TTS\TtsAudioFormat;
use GinoPane\PHPolyglot\Exception\InvalidContentTypeException;
use GinoPane\PHPolyglot\Exception\InvalidAudioFormatCodeException;
use GinoPane\PHPolyglot\Exception\InvalidAudioFormatParameterException;

/**
 * Trait IbmWatsonAudioFormatsTrait
 *
 * @link https://console.bluemix.net/docs/services/text-to-speech/http.html#format
 *
 * @author Sergey <Gino Pane> Karavay
 */
trait IbmWatsonAudioFormatsTrait
{
    /**
     * TTS audio format codes to IBM-Watson-specific codes mapping
     *
     * @var array
     */
    private static $formatMapping = [
        TtsAudioFormat::AUDIO_BASIC => IbmWatsonAudioFormatsInterface::AUDIO_BASIC,
        TtsAudioFormat::AUDIO_FLAC  => IbmWatsonAudioFormatsInterface::AUDIO_FLAC,
        TtsAudioFormat::AUDIO_L16   => IbmWatsonAudioFormatsInterface::AUDIO_L16,
        TtsAudioFormat::AUDIO_MP3   => IbmWatsonAudioFormatsInterface::AUDIO_MP3,
        TtsAudioFormat::AUDIO_MPEG  => IbmWatsonAudioFormatsInterface::AUDIO_MPEG,
        TtsAudioFormat::AUDIO_MULAW => IbmWatsonAudioFormatsInterface::AUDIO_MULAW,
        TtsAudioFormat::AUDIO_OGG   => IbmWatsonAudioFormatsInterface::AUDIO_OGG,
        TtsAudioFormat::AUDIO_WAV   => IbmWatsonAudioFormatsInterface::AUDIO_WAV,
        TtsAudioFormat::AUDIO_WEBM  => IbmWatsonAudioFormatsInterface::AUDIO_WEBM
    ];

    /**
     * Returns the string containing the accept parameter required for TTS.
     * It specifies audio format, sample rate and additional params if any
     *
     * @param TtsAudioFormat $format
     * @param array          $additionalData
     *
     * @throws InvalidAudioFormatCodeException
     * @throws InvalidAudioFormatParameterException
     *
     * @return string
     */
    public function getAcceptParameter(TtsAudioFormat $format, array $additionalData = []): string
    {
        $audioFormat = self::$formatMapping[$format->getFormat()] ?? '';

        if (empty($audioFormat)) {
            throw new InvalidAudioFormatCodeException($format->getFormat());
        }

        $accept = array_merge([$audioFormat], $this->processAdditionalParameters($format, $additionalData));

        return implode(";", $accept);
    }

    /**
     * @param Headers $headers
     *
     * @return TtsAudioFormat
     *
     * @throws InvalidContentTypeException
     */
    public function getAudioFormatByContentTypeHeader(Headers $headers): TtsAudioFormat
    {
        if (is_null($header = $headers->getHeader('content-type'))) {
            throw new InvalidContentTypeException("Response content-type is invalid or empty");
        }

        preg_match('/([^;]+)[;]?/', $header, $matches);

        if (empty($matches[1]) || !in_array($matches[1], self::$formatMapping)) {
            throw new InvalidContentTypeException(
                sprintf("Cannot extract audio format from content type: \"%s\"", $header)
            );
        }

        return new TtsAudioFormat((string)array_search($matches[1], self::$formatMapping));
    }

    /**
     * @param TtsAudioFormat $format
     * @param array          $additionalData
     *
     * @throws InvalidAudioFormatParameterException
     *
     * @return array
     */
    private function processAdditionalParameters(TtsAudioFormat $format, array $additionalData = []): array
    {
        $additional = [];

        switch ($format->getFormat()) {
            case TtsAudioFormat::AUDIO_FLAC:
            case TtsAudioFormat::AUDIO_MP3:
            case TtsAudioFormat::AUDIO_MPEG:
            case TtsAudioFormat::AUDIO_WAV:
                $additional[] = $this->extractRate($additionalData);

                break;
            case TtsAudioFormat::AUDIO_OGG:
                $additional[] = $this->extractRate($additionalData);
                $additional[] = $this->extractCodec($additionalData);

                break;
            case TtsAudioFormat::AUDIO_L16:
            case TtsAudioFormat::AUDIO_MULAW:
                $additional[] = $this->extractRate($additionalData, true);

                break;
            case TtsAudioFormat::AUDIO_WEBM:
                $codec = $this->extractCodec($additionalData);

                if ($codec == ("codecs=" . IbmWatsonAudioFormatsInterface::CODEC_VORBIS)) {
                    $additional[] = $this->extractRate($additionalData);
                }

                $additional[] = $codec;

                break;
        }

        return array_filter($additional);
    }

    /**
     * @param string $codec
     *
     * @return bool
     */
    private function codecIsValid(string $codec): bool
    {
        return in_array(
            $codec, //@codeCoverageIgnore
            [
                IbmWatsonAudioFormatsInterface::CODEC_OPUS,
                IbmWatsonAudioFormatsInterface::CODEC_VORBIS
            ]
        );
    }

    /**
     * @param array $additionalData
     *
     * @return mixed
     * @throws InvalidAudioFormatParameterException
     */
    private function extractCodec(array $additionalData)
    {
        $codec = $this->extractOptionalParameter('codec', $additionalData);

        if ($codec && !$this->codecIsValid($codec)) {
            throw new InvalidAudioFormatParameterException(
                sprintf("Specified codec \"%s\" is invalid", $codec)
            );
        }

        return "codecs=$codec";
    }

    /**
     * @param array $additionalData
     * @param bool  $required
     *
     * @throws InvalidAudioFormatParameterException
     *
     * @return mixed
     */
    private function extractRate(array $additionalData, bool $required = false)
    {
        $rateString = '';

        if ($required) {
            $rate = (int)$this->extractRequiredParameter('rate', $additionalData);
        } else {
            $rate = (int)$this->extractOptionalParameter('rate', $additionalData);
        }

        if ($rate) {
            $rateString = "rate=$rate";
        }

        return $rateString;
    }

    /**
     * @param string $parameter
     * @param array  $data
     *
     * @throws InvalidAudioFormatParameterException
     *
     * @return mixed
     */
    private function extractRequiredParameter(string $parameter, array $data)
    {
        if (!isset($data[$parameter])) {
            throw new InvalidAudioFormatParameterException(
                sprintf("Parameter \"%s\" is required", $parameter)
            );
        }

        return $data[$parameter];
    }

    /**
     * @param string $parameter
     * @param array  $data
     *
     * @return mixed|null
     */
    private function extractOptionalParameter(string $parameter, array $data)
    {
        if (isset($data[$parameter])) {
            return $data[$parameter];
        }

        return null;
    }
}