/// <summary>
        /// Read the ID3 meta data extracting required tag values
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="majorVersion"></param>
        /// <param name="maxPosition"></param>
        /// <param name="tags"></param>
        private static void ReadFrames(BinaryReader reader, int majorVersion, int maxPosition, MP3Tags tags)
        {
            // These are the tags that are currently being searched for
            HashSet <string> requiredTags = (majorVersion == 2) ? new HashSet <string>()
            {
                "TP1", "TP2", "TT2", "TAL", "TRK", "TYE", "TCO"
            }
                                        : new HashSet <string>()
            {
                "TPE1", "TPE2", "TIT2", "TALB", "TRCK", "TYER", "TCON"
            };

            int nameSize = (majorVersion == 2) ? 3 : 4;

            // Put the tag contents here
            Dictionary <string, byte[]> frames = new Dictionary <string, byte[]>();

            bool endOfTags = false;

            while ((reader.BaseStream.Position < maxPosition) && (endOfTags == false))
            {
                Logger.Log(string.Format("Position at start of frame {0}", reader.BaseStream.Position));

                // Check for end of the frames
                char frameNameFirstChar = reader.ReadChar();
                if (frameNameFirstChar == '\0')
                {
                    endOfTags = true;
                }
                else
                {
                    // Get the rest of the tag name and its contents
                    string frameName = frameNameFirstChar + new string( reader.ReadChars(nameSize - 1));

                    ulong frameSize = ReadFrameSize(reader, nameSize, majorVersion);

                    Logger.Log(string.Format("Frame {0}, size {1}", frameName, frameSize));

                    // Skip a couple of bytes and then read the frame contents
                    reader.ReadByte();
                    reader.ReadByte();

                    // Only store if it is one of the required tags
                    if (requiredTags.Contains(frameName) == true)
                    {
                        frames[frameName] = (frameSize > 0) ? reader.ReadBytes(( int )frameSize) : new byte[0];
                        requiredTags.Remove(frameName);
                        endOfTags = (requiredTags.Count == 0);
                    }
                    else
                    {
                        // Still need to skip over the frame contents
                        if (frameSize > 0)
                        {
                            Logger.Log(string.Format("Position before skipping {0} bytes is {1}", frameSize, reader.BaseStream.Position));
                            reader.ReadBytes(( int )frameSize);
                            Logger.Log(string.Format("Position after skipping bytes {0}", reader.BaseStream.Position));
                        }
                    }
                }
            }

            // Now all the required frames have been obtained, extract the contents and assign to the tag instance
            if (majorVersion == 2)
            {
                tags.Artist      = GetStringTag(frames, "TP1");
                tags.AlbumArtist = GetStringTag(frames, "TP2");
                tags.Title       = GetStringTag(frames, "TT2");
                tags.Album       = GetStringTag(frames, "TAL");
                tags.Track       = GetStringTag(frames, "TRK");
                tags.Year        = GetStringTag(frames, "TYE");
                tags.Genre       = GetStringTag(frames, "TCO");
            }
            else
            {
                tags.Artist      = GetStringTag(frames, "TPE1");
                tags.AlbumArtist = GetStringTag(frames, "TPE2");
                tags.Title       = GetStringTag(frames, "TIT2");
                tags.Album       = GetStringTag(frames, "TALB");
                tags.Track       = GetStringTag(frames, "TRCK");
                tags.Year        = GetStringTag(frames, "TYER");
                tags.Genre       = GetStringTag(frames, "TCON");
            }

            //			Log.WriteLine( LogPriority.Debug, "MobileApp:ReadFrames", string.Format( "Artist: {0} Title: {1} Album: {2} Track: {3}", tags.Artist, tags.Title, tags.Album,
            //				tags.Track ) );
        }
        /// <summary>
        /// Extract MP3 tags and duration from the MP3 stream
        /// </summary>
        /// <param name="fileStream"></param>
        /// <returns></returns>
        public static MP3Tags GetFileTags(Stream fileStream)
        {
            MP3Tags tags = new MP3Tags();

            using (BinaryReader reader = new BinaryReader(fileStream))
            {
                try
                {
                    // Make sure the file is at least 10 bytes long to determine the size of the ID3 header
                    if (reader.BaseStream.Length >= 10)
                    {
                        // Look at the start of the file for the ID3 tags
                        if (new string( reader.ReadChars(3)) == "ID3")
                        {
                            // Start extracting metadata
                            // ID3 version
                            byte majorVersion = reader.ReadByte();

                            // Skip the minor version
                            reader.ReadByte();

                            // Skip next 'flags' byte
                            reader.ReadByte();

                            // The size of the ID3 header
                            ulong headerSize = ReadEncodedSize(reader, 4);
                            if (headerSize > 0)
                            {
                                // Get all the required ID3 tags
                                int id3EndPosition = ( int )headerSize + 10;
                                ReadFrames(reader, majorVersion, id3EndPosition, tags);

                                // Step on past the ID3 frames and attempt to read the first MP3 frame
                                if ((reader.BaseStream.Position < id3EndPosition) && (reader.BaseStream.Length >= id3EndPosition))
                                {
                                    reader.ReadBytes(id3EndPosition - ( int )reader.BaseStream.Position);

                                    // The first MP3 frame does not always follow the end of the ID3 header, so go searching for the
                                    // MP3 synch pattern
                                    bool mp3HeaderFound = false;
                                    long readLimit      = reader.BaseStream.Position + 0x1000;
                                    long searchStart    = reader.BaseStream.Position;

                                    byte[] mp3Header = new byte[] { 0, 0, 0 };

                                    while ((mp3HeaderFound == false) && (reader.BaseStream.Position < reader.BaseStream.Length) &&
                                           (reader.BaseStream.Position < readLimit))
                                    {
                                        mp3Header[1] = reader.ReadByte();
                                        if ((mp3Header[0] == 0xFF) && ((mp3Header[1] & 0xE0) == 0xE0))
                                        {
                                            // Synch bytes found
                                            mp3HeaderFound = true;

                                            // Get the last byte of the header
                                            mp3Header[2] = reader.ReadByte();

                                            // Parse the MP3 frame and determine the duration of the file
                                            tags.Length = ParseMp3Frame(reader, mp3Header);
                                        }
                                        else
                                        {
                                            mp3Header[0] = mp3Header[1];
                                        }
                                    }

                                    if (mp3HeaderFound == false)
                                    {
                                        Logger.Log(string.Format("MP3 frame not found between {0} and {1}", searchStart, reader.BaseStream.Position));
                                    }
                                }
                                else
                                {
                                    Logger.Log(string.Format("ID3 frame is truncated"));
                                }
                            }
                        }
                        else
                        {
                            Logger.Log(string.Format("Header is not ID3"));
                        }
                    }
                    else
                    {
                        Logger.Log(string.Format("Could not read header"));
                    }
                }
                catch (Exception tagsException)
                {
                    Logger.Log(string.Format("Problem reading file: {0}", tagsException.Message));
                }
            }

            return(tags);
        }