예제 #1
0
        /**
         * This method reads the key specified in PollyProperties and sets it as the new AWS profile.
         * At the moment, the region is always set to EU which is something you might want to care for.
         * Except for setting up the account, it is not used or verified at this point.
         * The method only fails if there is something wrong with the KeyFile.
         */
        private void SetAwsProfile(PollyProperties pollyProps)
        {
            // Read the Credentials and store them shortly in an array
            var path = pollyProps.ApiKey;

            var credentialFile = new Dictionary <string, string>();

            foreach (var row in File.ReadAllLines(path))
            {
                credentialFile.Add(row.Split('=')[0], string.Join("=", row.Split('=').Skip(1).ToArray()));
            }

            // Create Amazon Credentials
            var options = new CredentialProfileOptions
            {
                AccessKey = credentialFile["AWSAccessKeyId"],
                SecretKey = credentialFile["AWSSecretKey"]
            };
            // Make Amazon Credential profile
            var profile = new Amazon.Runtime.CredentialManagement.CredentialProfile("polly_profile", options);

            profile.Region = RegionEndpoint.EUCentral1;

            this._awsProfile = profile;
        }
예제 #2
0
        /*
         * Makes a new savepoint at index+1.
         * If the point is already known, do nothing.
         * If a new Point is created while the Memento is in a position of the past,
         * all history after the current point will be lost.
         */
        public void MakeMemento(PollyProperties ps)
        {
            var memento = (PollyProperties)ps.Clone();

            // Short-Circuit:
            // memento is already in history - do nothing, return early.
            if (_history.Contains(memento))
            {
                return;
            }

            // Case 1: Current Index is last of List
            if (_history.Count == 0 || _index == -1 || _index == _history.Count - 1)
            {
                // "Just" add a copy of current Properties to Memento List
                _history.Add(memento);
                // Increase Index by 1
                _index++;
            }
            // Case 2: Current Index is not last of the list
            else
            {
                // Drop all items after index, "make current index last index"
                this._history = _history.GetRange(0, this._index);
                // Do Case 1
                _history.Add(memento);
                _index++;
            }
        }
예제 #3
0
        public object Clone()
        {
            // Cloning is rather easy, as Strings are pass by value (so is the int of sampling rate)
            var clone = new PollyProperties()
            {
                Voice        = this.Voice,
                ApiKey       = this.ApiKey,
                TextToPlay   = this.TextToPlay,
                SamplingRate = this.SamplingRate
            };

            return(clone);
        }
예제 #4
0
        /**
         * This method reads the polly props and creates a hashcode for it.
         * The used hash-method is MD5, which gets cut down to 8 digits.
         * The number of digits is at the moment hardcoded in the PollyCaller as a constant.
         * The hashed properties are Text, Voice & SamplingRate.
         */
        private string DeriveTemporaryName(PollyProperties pollyProps)
        {
            var    input = pollyProps.TextToPlay + "+" + pollyProps.Voice + "+" + pollyProps.SamplingRate;
            string output;

            using (var provider = System.Security.Cryptography.MD5.Create())
            {
                var builder = new StringBuilder();
                foreach (byte b in provider.ComputeHash(Encoding.UTF8.GetBytes(input)))
                {
                    builder.Append(b.ToString("x2").ToLower());
                }
                output = builder.ToString();
            }

            return(output.Substring(0, PollyCaller.HashCodeLength));
        }
예제 #5
0
        /*
         * This method reads the polly properties and audio-properties,
         * then it checks if the wanted combination of text+voice is known already.
         * If the text is known, it will be saved to the given filename,
         * otherwise it will be created by Amazon, stored locally and then saved.
         */
        public void SaveToFile(string mp3Filename, PollyProperties pollyProps)
        {
            // There was an issue, when the stream was already played.
            // If that was the case, the stream was "at an end" and could not be saved somewhere (file was just empty).
            // So if the sound was played, there should be a temp file for it which we just move.
            // If the file is not there - remove the key and run again.

            SetAwsProfile(pollyProps);
            string tempName     = DeriveTemporaryName(pollyProps);
            string tempFilePath = Path.GetFullPath(tempName + ".mp3", _soundDir.FullName);

            if (_knownHashes.ContainsKey(tempName))
            {
                if (File.Exists(tempFilePath))
                {
                    File.Copy(tempFilePath, mp3Filename);
                }
                else
                {
                    // The file got lost - that's bad.
                    // Remove the key, and re-run again. This will also create the file.
                    _knownHashes.Remove(tempName);
                    SaveToFile(mp3Filename, pollyProps);
                }
            }
            else // The hash is not known - create it and make the file + temp file
            {
                Stream audioStream = MakeAwsCall(pollyProps);
                _knownHashes[tempName] = audioStream;
                // I am not 100% sure, but overwriting did not properly work for audio-streams.
                if (File.Exists(mp3Filename))
                {
                    File.Delete(mp3Filename);
                }

                // use two file-streams, to still save it to temp
                using (FileStream fs = File.Create(mp3Filename))
                    using (FileStream tfs = File.Create(tempFilePath))
                    {
                        audioStream.CopyTo(fs);
                        audioStream.CopyTo(tfs);
                        fs.Flush();
                        tfs.Flush();
                    }
            }
        }
예제 #6
0
        /*
         * This method reads the polly properties and audioproperties,
         * then it checks if the wanted combination of text+voice is known already.
         * If the text is known, it will be played to the selected audiodevices,
         * otherwise it will be created by Amazon, stored locally and then played.
         */
        public void Call(PollyProperties pollyProps)
        {
            SetAwsProfile(pollyProps);

            var tempName     = DeriveTemporaryName(pollyProps);
            var tempFilePath = Path.GetFullPath(tempName + ".mp3", _soundDir.FullName);

            Stream audioStream = null;

            if (_knownHashes.ContainsKey(tempName))
            {
                audioStream = _knownHashes[tempName];
            }
            else
            {
                audioStream            = MakeAwsCall(pollyProps);
                _knownHashes[tempName] = audioStream;
            }

            if (!File.Exists(tempFilePath))
            {
                /*TODO: Without the existence check, the line below throws a marshal-error
                 * /*The file-handle does not seem to be closed properly.
                 */
                using (FileStream fs = File.Create(tempFilePath))
                {
                    audioStream.CopyTo(fs);
                    fs.Flush();
                }
            }

            // The audio-devices must be decremented by one, as the "default" for NAudio is -1 while its 0 for Windows.
            PlaySound(tempFilePath, AudioProps.DeviceA - 1, AudioProps.VolumeA);
            // Just play the second audio if there is a different selected
            if (AudioProps.DeviceA != AudioProps.DeviceB)
            {
                PlaySound(tempFilePath, AudioProps.DeviceB - 1, AudioProps.VolumeB);
            }
        }
예제 #7
0
        /*
         * This method reads the polly properties and the ready-made AWS Profile to send a polly request.
         * It returns the Stream of the MP3 created.
         *
         * This method will likely fail in three ways:
         * 1) The Profile is bad
         * 2) The user is offline
         * 3) The specified content for the request is faulty
         *
         * I tried to address the 3) with value checks in the frontend, the others are not checked for at the moment.
         */
        private Stream MakeAwsCall(PollyProperties pollyProps)
        {
            // Store the Amazon Profile in the Credentials Engine for later use
            var netSdkFile = new NetSDKCredentialsFile();

            netSdkFile.RegisterProfile(_awsProfile);

            // This chain uses the credentials to create a token for usage,
            // Later the token is used in the Credentials
            // The chain stores it into awsCredentials, that is used for the client.
            var            chain = new CredentialProfileStoreChain();
            AWSCredentials awsCredentials;
            Stream         audioStream = null;

            // use awsCredentials
            if (chain.TryGetAWSCredentials("polly_profile", out awsCredentials))
            {
                using (var client = new AmazonPollyClient(awsCredentials, _awsProfile.Region))
                {
                    var response = client.SynthesizeSpeechAsync(new SynthesizeSpeechRequest
                    {
                        OutputFormat = "mp3",
                        SampleRate   = pollyProps.SamplingRate.ToString(),
                        Text         = pollyProps.TextToPlay,
                        TextType     = "text",
                        VoiceId      = pollyProps.Voice // One of Hans, Jenny , ...
                    });
                    response.Wait();

                    var res = response.Result;
                    audioStream = res.AudioStream;
                }
            }

            return(audioStream);
        }