| 59 | } |
| 60 | |
| 61 | AudioDecoder* AudioDecoderManager::createDecoder(std::string_view path) |
| 62 | { |
| 63 | if (cxx20::ic::ends_with(path, ".ogg") || cxx20::ic::ends_with(path, ".opus")) |
| 64 | { |
| 65 | constexpr char VORBIS_SIGN[] = {0x1, 'v', 'o', 'r', 'b', 'i', 's', '\0'}; |
| 66 | constexpr char OPUS_SIGN[] = {'O', 'p', 'u', 's', 'H', 'e', 'a', 'd'}; |
| 67 | constexpr int OGG_CODEC_SIGN_OFFSET = 28; |
| 68 | constexpr int OGG_CODEC_SIGN_SIZE = 8; |
| 69 | |
| 70 | auto stream = FileUtils::getInstance()->openFileStream(path, IFileStream::Mode::READ); |
| 71 | if (!stream) |
| 72 | return nullptr; |
| 73 | if (stream->size() < OGG_CODEC_SIGN_OFFSET + OGG_CODEC_SIGN_SIZE) |
| 74 | { |
| 75 | return nullptr; |
| 76 | } |
| 77 | stream->seek(OGG_CODEC_SIGN_OFFSET, SEEK_SET); |
| 78 | char codecSign[OGG_CODEC_SIGN_SIZE]; |
| 79 | stream->read(codecSign, OGG_CODEC_SIGN_SIZE); |
| 80 | stream->seek(0, SEEK_SET); |
| 81 | |
| 82 | if (memcmp(codecSign, VORBIS_SIGN, OGG_CODEC_SIGN_SIZE) == 0) |
| 83 | { |
| 84 | return new AudioDecoderVorbis(stream.release()); |
| 85 | } |
| 86 | #if defined(AX_ENABLE_OPUS) |
| 87 | else if (memcmp(codecSign, OPUS_SIGN, OGG_CODEC_SIGN_SIZE) == 0) |
| 88 | { |
| 89 | return new AudioDecoderOpus(stream.release()); |
| 90 | } |
| 91 | #endif |
| 92 | else |
| 93 | { |
| 94 | AXLOGE("Fail create decoder due to codec error in file: {}", path); |
| 95 | return nullptr; |
| 96 | } |
| 97 | } |
| 98 | #if !defined(__APPLE__) |
| 99 | else if (cxx20::ic::ends_with(path, ".mp3")) |
| 100 | { |
nothing calls this directly
no test coverage detected