Bloom.Publish.EpubMaker.AddAudioOverlay C# (CSharp) Method

AddAudioOverlay() private method

Create an audio overlay for the page if appropriate. We are looking for the page to contain spans with IDs. For each such ID X, we look for a file _storage.FolderPath/audio/X.mp{3,4}. If we find at least one such file, we create pageDocName_overlay.smil with appropriate contents to tell the reader how to read all such spans aloud.
private AddAudioOverlay ( HtmlDom pageDom, string pageDocName ) : void
pageDom Bloom.Book.HtmlDom
pageDocName string
return void
        private void AddAudioOverlay(HtmlDom pageDom, string pageDocName)
        {
            var spansWithIds = pageDom.RawDom.SafeSelectNodes(".//span[@id]").Cast<XmlElement>();
            var spansWithAudio =
                spansWithIds.Where(x =>GetOrCreateCompressedAudioIfWavExists(x.Attributes["id"].Value) != null);
            if (!spansWithAudio.Any())
                return;
            var overlayName = GetOverlayName(pageDocName);
            _manifestItems.Add(overlayName);
            string smilNamespace = "http://www.w3.org/ns/SMIL";
            XNamespace smil = smilNamespace;
            string epubNamespace = "http://www.idpf.org/2007/ops";
            XNamespace epub = epubNamespace;
            var seq = new XElement(smil+"seq",
                new XAttribute("id", "id1"), // all <seq> I've seen have this, not sure whether necessary
                new XAttribute(epub + "textref", pageDocName),
                new XAttribute(epub + "type", "bodymatter chapter") // only type I've encountered
                );
            var root = new XElement(smil + "smil",
                new XAttribute( "xmlns", smilNamespace),
                new XAttribute(XNamespace.Xmlns + "epub", epubNamespace),
                new XAttribute("version", "3.0"),
                new XElement(smil + "body",
                    seq));
            int index = 1;
            TimeSpan pageDuration = new TimeSpan();
            foreach (var span in spansWithAudio)
            {
                var spanId = span.Attributes["id"].Value;
                var path = GetOrCreateCompressedAudioIfWavExists(spanId);
                var dataDurationAttr = span.Attributes["data-duration"];
                if (dataDurationAttr != null)
                {
                    pageDuration += TimeSpan.FromSeconds(Double.Parse(dataDurationAttr.Value));
                }
                else
                {
                    //var durationSeconds = TagLib.File.Create(path).Properties.Duration.TotalSeconds;
                    //duration += new TimeSpan((long)(durationSeconds * 1.0e7)); // argument is in ticks (100ns)
                    // Haven't found a good way to get duration from MP3 without adding more windows-specific
                    // libraries. So for now we'll figure it from the wav if we have it. If not we do a very
                    // crude estimate from file size. Hopefully good enough for BSV animation.
                    var wavPath = Path.ChangeExtension(path, "wav");
                    if (RobustFile.Exists(wavPath))
                    {
            #if __MonoCS__
                        pageDuration += new TimeSpan(new FileInfo(path).Length);	// TODO: this needs to be fixed for Linux/Mono
            #else
                        using (WaveFileReader wf = RobustIO.CreateWaveFileReader(wavPath))
                            pageDuration += wf.TotalTime;
            #endif
                    }
                    else
                    {
                        NonFatalProblem.Report(ModalIf.All, PassiveIf.All,
                            "Bloom could not find one of the expected audio files for this book, nor a precomputed duration. Bloom can only make a very rough estimate of the length of the mp3 file.");
                        // Crude estimate. In one sample, a 61K mp3 is 7s long.
                        // So, multiply by 7 and divide by 61K to get seconds.
                        // Then, to make a TimeSpan we need ticks, which are 0.1 microseconds,
                        // hence the 10000000.
                        pageDuration += new TimeSpan(new FileInfo(path).Length*7*10000000/61000);
                    }
                }
                var epubPath = CopyFileToEpub(path);
                seq.Add(new XElement(smil+"par",
                    new XAttribute("id", "s" + index++),
                    new XElement(smil + "text",
                        new XAttribute("src", pageDocName + "#" + spanId)),
                        new XElement(smil + "audio",
                            // Note that we don't need to preserve any audio/ in the path.
                            // We now mangle file names so as to replace any / (with _2f) so all files
                            // are at the top level in the ePUB. Makes one less complication for readers.
                            new XAttribute("src", Path.GetFileName(epubPath)))));
            }
            _pageDurations[GetIdOfFile(overlayName)] = pageDuration;
            var overlayPath = Path.Combine(_contentFolder, overlayName);
            using (var writer = XmlWriter.Create(overlayPath))
                root.WriteTo(writer);
        }