예제 #1
0
        public async Task <IHttpActionResult> GetFromFreeswitch(string uuid, int userId = 0)
        {
            RecordingDetails result = null;

            // Produce file paths.
            var workDirPath    = GeneralUtils.GetAppDataDir();
            var sourceFilePath = Path.Combine(workDirPath, uuid + ".wav");
            var outputFilePath = Path.ChangeExtension(sourceFilePath, "mp3");

            // The path structure in the Blob Storage is userIdKey/timeKey/filename.ext
            var userIdKey      = KeyUtils.IntToKey(userId);
            var timeKey        = KeyUtils.GetTimeAsBase32();
            var outputBlobName = String.Format("{0}/{1}/{2}.mp3", userIdKey, timeKey, uuid);
            var logBlobName    = Path.ChangeExtension(outputBlobName, "log");

            try
            {
                // Convert to MP3. Increase the audio volume by 10dB, convert to MP3 CBR 64kbit/s.
                var arguments = String.Format("-i \"{0}\" -af \"volume=10dB\" -b:a 64k \"{1}\"", sourceFilePath, outputFilePath);
                var logText   = RecordingUtils.RunFfmpeg(arguments);

                var containerName = AzureStorageUtils.ContainerNames.Artifacts;
                var taskMp3       = AzureStorageUtils.UploadFromFileAsync(outputFilePath, containerName, outputBlobName, "audio/mpeg");
                var taskLog       = AzureStorageUtils.UploadTextAsync(logText, containerName, logBlobName, "text/plain");
                // Upload the blobs simultaneously.
                await Task.WhenAll(taskMp3, taskLog);

                // Get the recording's duration.
                var duration = RecordingUtils.GetDurationFromFfmpegLogOrMp3File(logText, outputFilePath);

                // Delete the original WAV file on success.
                File.Delete(sourceFilePath);

                // The JSON encoder with default settings doesn't make upper-case -> lower-case letter conversion of property names. The receiving side is case-sensitive.
                result = new RecordingDetails
                {
                    BlobName      = outputBlobName,
                    TotalDuration = duration,
                };
            }
            finally
            {
                // Clean up the MP3 file anyway.
                File.Delete(outputFilePath);
            }

            return(Ok <RecordingDetails>(result));
        }
예제 #2
0
    // Get the recording details from the XML file returned by the web request
    RecordingDetails GetRecordingDetails()
    {
        WWW www = new WWW(GetRecordingDetailsURL);

        while (!www.isDone)
        {
        }
        if (debugActive)
        {
            Debug.Log(www.text);
        }
        System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader(new System.IO.StringReader(www.text));
        string newestID        = "";
        string newestStartTime = "";
        string newestStopTime  = "";

        while (reader.Read())
        {
            string newID        = reader.GetAttribute("recordingid");
            string newStartTime = reader.GetAttribute("starttime");
            string newStopTime  = reader.GetAttribute("stoptime");

            if (newID != null)
            {
                newestStartTime = newStartTime;
                newestStopTime  = newStopTime;
                newestID        = newID;
            }
        }

        RecordingDetails output = new RecordingDetails();

        output.recordingID = newestID;
        output.startTime   = newestStartTime;
        output.stopTime    = newestStopTime;

        details.collected = true;
        return(output);
    }
예제 #3
0
        public async Task <RecordingDetails> Transcode(IEnumerable <KeyValuePair <string, MemoryStream> > tracks, string userIdKey, string timeKey, string extension)
        {
            RecordingDetails result = null;

            // ffmpeg.exe works with files. Produce file paths.
            var workDirPath    = GeneralUtils.GetAppDataDir();
            var fileNamePrefix = userIdKey + "_" + timeKey;

            var trackItems = tracks
                             .Select(i => new TrackItem
            {
                Name             = i.Key,
                Stream           = i.Value,
                OriginalFile     = Path.Combine(workDirPath, String.Format("{0}_{1}.{2}", fileNamePrefix, i.Key, extension)),
                IntermidiateFile = Path.Combine(workDirPath, String.Format("{0}_{1}_intermidiate.mp3", fileNamePrefix, i.Key)),
            })
                             .ToList();

            var inputListFilePath = Path.Combine(workDirPath, fileNamePrefix + ".txt");
            var outputFilePath    = Path.ChangeExtension(inputListFilePath, ".mp3");

            const string resultFileName = "result";
            var          outputBlobName = ExerciseUtils.FormatBlobName(userIdKey, timeKey, resultFileName, "mp3");
            var          logBlobName    = ExerciseUtils.FormatBlobName(userIdKey, timeKey, resultFileName, "log");

            try
            {
                // Save the original tracks to the disk.
                foreach (var i in trackItems)
                {
                    using (FileStream stream = new FileStream(i.OriginalFile, FileMode.Create, FileAccess.Write))
                    {
                        i.Stream.WriteTo(stream);
                    }
                }

                // Convert to MP3.
                // ffmpeg fails to concatenate AMRs, the error text is misleading "mylistfile.txt: Input/output error". We convert each file separately, then concatenate MP3s.
                foreach (var i in trackItems)
                {
                    // Increase audio volume by 10dB, convert to MP3 CBR 32kbit/s.
                    var arguments = String.Format("-i \"{0}\" -af \"volume=10dB\" -b:a 32k \"{1}\"", i.OriginalFile, i.IntermidiateFile);
                    i.Log = RecordingUtils.RunFfmpeg(arguments);
                }

                // Pass the file names to concatenate to ffmpeg.exe in a text file.
                var inputListLines = trackItems.Select(i => String.Format("file '{0}'", i.IntermidiateFile));
                File.WriteAllLines(inputListFilePath, inputListLines);

                // Concatenate MP3s. Do not re-encode, copy existing streams as is.
                var concatArguments = String.Format("-f concat -i \"{0}\" -c copy \"{1}\"", inputListFilePath, outputFilePath);
                var resultLog       = RecordingUtils.RunFfmpeg(concatArguments);

                var separator = Environment.NewLine + "----------------------------------------" + Environment.NewLine;
                var logText   = String.Join(separator, trackItems.Select(i => i.Log))
                                + separator + String.Join(Environment.NewLine, inputListLines)
                                + separator + resultLog;

                var containerName = AzureStorageUtils.ContainerNames.Artifacts;
                var taskMp3       = AzureStorageUtils.UploadFromFileAsync(outputFilePath, containerName, outputBlobName, "audio/mpeg");
                var taskLog       = AzureStorageUtils.UploadTextAsync(logText, containerName, logBlobName, "text/plain");
                // Upload the blobs simultaneously.
                await Task.WhenAll(taskMp3, taskLog);

                // Get the recording durations.
                var trackDurations = trackItems
                                     .Select((i) =>
                {
                    var trackDuration = RecordingUtils.GetDurationFromFfmpegLogOrMp3File(i.Log, i.IntermidiateFile);
                    return(new KeyValuePair <string, decimal>(i.Name, trackDuration));
                })
                                     .ToDictionary(i => i.Key, i => i.Value)
                ;

                var duration = RecordingUtils.GetDurationFromFfmpegLogOrMp3File(resultLog, outputFilePath);

                // The JSON encoder with default settings doesn't make upper-case -> lower-case letter conversion of property names. The receiving side is case-sensitive.
                result = new RecordingDetails
                {
                    BlobName       = outputBlobName,
                    TotalDuration  = duration,
                    TrackDurations = trackDurations,
                };
            }
            finally
            {
                // Clean up the local disk.
                foreach (var i in trackItems)
                {
                    File.Delete(i.OriginalFile);
                    File.Delete(i.IntermidiateFile);
                }
                File.Delete(inputListFilePath);
                File.Delete(outputFilePath);
            }

            return(result);
        }