Properly mark classes as final
[alure.git] / src / decoders / mpg123.cpp
blob7fad2b20fe0e0cc76d0b2f319a1fe33142b3c955
2 #include "mpg123.hpp"
4 #include <stdexcept>
5 #include <iostream>
7 #include "mpg123.h"
9 namespace alure
12 static ssize_t r_read(void *user_data, void *ptr, size_t count)
14 std::istream *file = reinterpret_cast<std::istream*>(user_data);
16 file->clear();
17 file->read(reinterpret_cast<char*>(ptr), count);
18 return file->gcount();
21 static off_t r_lseek(void *user_data, off_t offset, int whence)
23 std::istream *file = reinterpret_cast<std::istream*>(user_data);
25 file->clear();
26 if(!file->seekg(offset, std::ios::seekdir(whence)))
27 return -1;
28 return file->tellg();
32 class Mpg123Decoder final : public Decoder {
33 UniquePtr<std::istream> mFile;
35 mpg123_handle *mMpg123;
36 int mChannels;
37 long mSampleRate;
39 public:
40 Mpg123Decoder(UniquePtr<std::istream> file, mpg123_handle *mpg123, int chans, long srate)
41 : mFile(std::move(file)), mMpg123(mpg123), mChannels(chans), mSampleRate(srate)
42 { }
43 ~Mpg123Decoder() override;
45 ALuint getFrequency() const override;
46 ChannelConfig getChannelConfig() const override;
47 SampleType getSampleType() const override;
49 uint64_t getLength() const override;
50 bool seek(uint64_t pos) override;
52 std::pair<uint64_t,uint64_t> getLoopPoints() const override;
54 ALuint read(ALvoid *ptr, ALuint count) override;
57 Mpg123Decoder::~Mpg123Decoder()
59 mpg123_close(mMpg123);
60 mpg123_delete(mMpg123);
61 mMpg123 = 0;
65 ALuint Mpg123Decoder::getFrequency() const
67 return mSampleRate;
70 ChannelConfig Mpg123Decoder::getChannelConfig() const
72 if(mChannels == 1)
73 return ChannelConfig::Mono;
74 if(mChannels == 2)
75 return ChannelConfig::Stereo;
76 throw std::runtime_error("Unsupported sample configuration");
79 SampleType Mpg123Decoder::getSampleType() const
81 return SampleType::Int16;
85 uint64_t Mpg123Decoder::getLength() const
87 off_t len = mpg123_length(mMpg123);
88 return (ALuint)std::max<off_t>(len, 0);
91 bool Mpg123Decoder::seek(uint64_t pos)
93 off_t newpos = mpg123_seek(mMpg123, pos, SEEK_SET);
94 if(newpos < 0) return false;
95 return true;
98 std::pair<uint64_t,uint64_t> Mpg123Decoder::getLoopPoints() const
100 return std::make_pair(0, 0);
103 ALuint Mpg123Decoder::read(ALvoid *ptr, ALuint count)
105 unsigned char *dst = reinterpret_cast<unsigned char*>(ptr);
106 ALuint bytes = count * mChannels * 2;
107 ALuint total = 0;
108 while(total < bytes)
110 size_t got = 0;
111 int ret = mpg123_read(mMpg123, dst+total, bytes-total, &got);
112 if((ret != MPG123_OK && ret != MPG123_DONE) || got == 0)
113 break;
115 total += got;
116 if(ret == MPG123_DONE)
117 break;
119 return total / mChannels / 2;
123 Mpg123DecoderFactory::Mpg123DecoderFactory()
124 : mIsInited(false)
126 if(!mIsInited)
128 if(mpg123_init() == MPG123_OK)
129 mIsInited = true;
133 Mpg123DecoderFactory::~Mpg123DecoderFactory()
135 if(mIsInited)
136 mpg123_exit();
137 mIsInited = false;
141 SharedPtr<Decoder> Mpg123DecoderFactory::createDecoder(UniquePtr<std::istream> &file)
143 if(!mIsInited)
144 return nullptr;
146 mpg123_handle *mpg123 = mpg123_new(0, 0);
147 if(mpg123)
149 if(mpg123_replace_reader_handle(mpg123, r_read, r_lseek, 0) == MPG123_OK &&
150 mpg123_open_handle(mpg123, file.get()) == MPG123_OK)
152 int enc, channels;
153 long srate;
155 if(mpg123_getformat(mpg123, &srate, &channels, &enc) == MPG123_OK)
157 if((channels == 1 || channels == 2) && srate > 0 &&
158 mpg123_format_none(mpg123) == MPG123_OK &&
159 mpg123_format(mpg123, srate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK)
161 // All OK
162 return MakeShared<Mpg123Decoder>(std::move(file), mpg123, channels, srate);
165 mpg123_close(mpg123);
167 mpg123_delete(mpg123);
170 return nullptr;