Part 3/3
I'll reply in 3 parts:
Alernative A
As already hinted at in issue https://sourceforge.net/p/mpg123/bugs/330/, here are my suggestions for a new libmpg123 v2 API and ABI, resolving a lot of the portability issues in the current design.
mpg123v2.h should include stdint.h and stddef.h. stdlib.h (not needed) and sys/types.h (not portable) should go away.
fmt123.h should probably just move into mpg123v2.h. If not, it absolutely needs to be included as "fmt123v2.h". <fmt123.h> catches a system-installed one when developing mpg123 on a system where another version of libmpg123 is already installed system-wide.</fmt123.h>
All off_t should be replaced by int64_t. If desired, it could be split up into two typedefed symbolic types mpg123v2_off_t and mpg123v2_samplecount_t.
Replacing the raw int in enum APIs by a typedef int mpg123v2_enum could also improve clarity.
mpg123v2_ssize_t should unconditionally be ptrdiff_t. For all sane platforms, including POSIX and Windows, it is a signed type that has the same width as intptr_t/ssize_t/size_t/void*. In contrast to ssize_t, it is actually a portable type specified by C.
In libmpg123's implementation, almost all uses of long should be long long (or int64_t). This gives the most compatible selection of types across all major platforms, and in particular implies the same bitwidth on all of them. That combination of bitwidths is the one that already gets tested the most (on 64bit POSIX platforms) anyway, and as it is the most common, it is also the one where it would be the easiest to run sanitizers on. I did not do any in-depth review yet, but I have already spotted cases (in particular all debug printf) where 64bit off_t causes integer overflow on ILP32 platforms due to use of long (this affects not only MSVC, but also 32bit POSIX x86 or 32bit POSIX ARM).
long is basically a useless type nowadays. I do understand that long long did not exist back in C89, however nowadays, the intended semantics (which are identical as currently on LP64) can be translated 1:1 to all platforms by replacing long by long long. Having internal types be of consistent bitwidth across different platforms significantly simplifies testing.
See https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models:
ILP32 LLP64 LP64
int 32 32 32
long 32 32 64
long long 64 64 64
void* 32 64 64
ILP32: Win32 / POSIX32
LLP64: Win64
LP64: POSIX64
Remove all preprocessor renaming trickery from the API. Remove all off_t APIs, remove all _32 APIs. The _64 may in theory stay, however I think breaking ABI completely would allow also cleaning up other problems that have creeped up over time.
mpg123v2.h should not depend on any build system variables. The only remaining offender after all other mentioned cleanups would be the API version. The build system should (if required) query the version from the header, not the other way around. That makes the header independent of any build system and makes it way easier to build/port libmpg123 with other build systems.
Rename all public API names from mpg123_/MPG123_ to mpg123v2_/MPG123V2_.
Rename the library to libmpg123v2.
mpg123_open only taking UTF-8 on Windows might look reasonable from a POSIX perspective, but it very much is not from a Windows perspective. Basically any Windows application that works with 8bit CHAR/char assumes that to be encoded in CP_ACP (that is roughly similar to the setlocale("") encoding on POSIX systems), which is almost never UTF-8 (it only ever can be UTF-8 on Windows 10 1903 or later, and whether it is is not controllable by a library). The correct way to open files on Windows is always to use WCHAR/wchar_t. However, the current libmpg123 API does not support that unless one uses mpg123_replace_reader. I suggest getting rid of local file opening in libmpg123 alltogether and ONLY having client code open via an explicitly provided reader (which can be assisted by a helper header file, as done in e.g. libvorbisfile or libopenmpt), relieving libmpg123 from dealing with fopen or off_t completely, even internally.
Providing a custom reader may arguably also be the better default as the most likely expected usecase for libmpg123 is being integrated in some player framework, which likely already has its own file abstraction anyway. The only user that actually prefers directly opening files may well be only mpg123 itself.
mpg123_open_fd is also not really useful on Windows ans can also just fine be handled completely by client code.
lfs_wrap and lfs_alias can be reworked into a header-only implementation of the old API on top of the new one. Another possibility would be to grow lfs_wrap into an actually ABI-compatible libmpg123 with the current API and ABI that internally just calls the new libmpg123v2. That would retain support for old ABI and API while also allowing to move forward with a cleaner ABI and API.
I would prefer to make intsyms.h go away. Navigating the source in IDEs is very much hindered by the confusing preprocessor renaming. All internal symbols could just use the internal name explicitly.
I do not mind using subversion. In fact I actually do prefer it over git myself. However, having at least a GitHub mirror would help making use of the free-to-use GitHub Actions CI as well as other free-to-use GitHub-based CIs like Cirrus-CI and AppVeyor. That would allow for a lot of automatic testing on all major platforms (using all 3 CIs can easily cover at least the following: Ubuntu, FreeBSD, Windows MSVC, Windows MSYS2, and macOS). Settting up a simple mirror script that basically only tracks trunk is a matter of ~2 hours. Setting up a full mirror, tracking all present and past branches and all intricate relations between them would be a lot of work however, given the non-standard layout and past svn history of the mpg123 repository. That would probably take a month to set up, including a lot of testing and going through history, reconstructing links that have not been properly recorded in svn history. I did do something like that once for the OpenMPT project (the result is a very clean git repository and ~12kB script that creates it by sticking all broken commit history in the early svn repository back together properly). I would rather not do that again, especially since I am not familiar with early mpg123 history.
I could maybe provide additional manual testing on some more weird/esoteric platforms:
Alternative B
I am writing this paragraph after having read your suggestions how to proceed.
Instead of how I propose things in A (breaking ABI/API, providing a header-only wrapper with the old API around the new one (13.)), another option might be to do as I suggest without renaming the library (1., 9., 10.) to v2 and without breaking ABI. I would still suggest providing a new clean-slate API header and ABI (7.), but the old API and ABI could continue to be implemented inside libmpg123 as a wrapper around the new exposed API (13.). To me, this looks like a good compromise of both our goals and also like a reasonable compromise regarding maintenance overhead. It also provides a clean future option to sometime maybe get rid of the legacy interfaces. I would be fine with not naming new symbols or headers mpg123v2 in that case.
If you are willing to break ABI and API, I am very much willing help implementing, or even offer to completely do all of it (it will take time of course, and doing it on a dedicated feature-branch is very much a must).
If you want to continue the ABI stability and keep all preprocessor renaming of symbols or even any off_t or POSIX type or header still appearing in the public header without claerly and explicitly deprecating the legacy interface, I would be way more hesitent to help. Maintaining that forever into the future will inevitably again cause maintenance overhead sometime. A clear break with removing or at least deprecating the problematic and confusing ABI/API can avoid that.
I will be taking some time considering the steps you propose. My initial reaction is laid out in the other bug. Maybe things change after some days (being busy with other things, anyway).
I do see your point that the file handling in libmpg123 seems overly eclectic. Some of that comes from it being born out of cutting code out of the mpg123 console player. There are frameworks that like to do their own I/O, and hence even the feeder API is popular there, but I got repeatedly complimented for the easy to use API … some folks actually write programs that load MP3s directly and they like doing open/read/close just like with a normal file. In the end, that's a minor thing for the library. It is a decision if you want the API to be absolutely minimal in symbol count, or if convenience wrappers should exist.
Before getting carried away in details, I just wanted to mention, on your point 15, that we do have a github mirror on https://github.com/madebr/mpg123 . It is mentioned on the download page, but it is semi-official only. We could add CI stuff there. Not sure what sf.net actually would offer here. Anyhow, I am not opposed to automatic testing. I have reservations about the main repo being on github, mainly because just about everyone is there and people assume that no other hosting exists. All eggs in one basket … don't like that just out of principle. I'd rather eye something like sourcehut. But maybe the github one would be needed for the Microsoft-friendly (surprise!) CI pipes. We do have nightly regression tests on Linux, but no platform port testing.
Anyhow, Let's see if I can chew on and digest this over the weekend. My hunch is that I'll go mostly with my plan — and do the work inside our codebase, but I do want to give your suggestions a fair chance of persuading me at least on some points.
Last edit: Thomas Orgis 2022-09-20
Damn, now I'm reading up on the history of long long in the standard. https://yarchive.net/comp/longlong.html funny read … especially the projections about computer hardware in 2020.
I'll pick up some points now. My thought is about extending the current mpg123 API, not replacing it, but most of your list still applies for the new stuff, I presume.
0. I am willing to offer a preprocessor switch that omits the
off_tandssize_tAPI (as the latter is tied tooff_t-using functions anyway). I won't call it deprecation, though. I am not intending to delete the other stuff during the lifetime of libmpg123 version 1. There might be a version 2 in the distant future, probably by someone else than me. That would also be the point where libmpg123 got fully split from mpg123 the application and the other libs, I guess. Right now, they share a deal of internal code, are developed together, and there's no benefit for the very small developer team in increasing the count of repositories.I hope you can limit the scope of the API relevant to you with that switch in mind and I have to worry about the other baggage.
I'll call it
MPG123_PORTABLE_APIfor now. I guess this should also hidempg123_open_fd()and the plainmpg123_replace_reader(), as it could be easily misused. Anything that opens questions regarding compatible toolchains, etc. What jumps into my eye there:Memory allocated inside libmpg123 and freed by the user. Dangerous. I could introduce a
mpg123_mem_free()for this purpose, just wrapping overfree()in the mpg123 build … but since this is a rather fringe use case and the same can be achieved usingmpg123_store_utf8(), just dropping the definition withMPG123_PORTABLE_APIis good enough.1. We need headers for
size_tand the types we intend to use. That'sstddef.hfor one, andstdint.hifint64_tenters the game. We getptrdiff_twith those, but notssize_tfor the non-portable API. Actually,ptrdiff_tfor something that is not a pointer difference irks me. I am currently leaning towards asking what's the deal with all the typedefs if we throw out semantics anyway … and just using longs, long longs or this-is-64-bit-integer.2. When
mpg123.his installed system-wide, it better should default to the system-widefmt123.h. If you want to use the local one, add-I.to flags. But then, include with quotes is implementation-defined, anyway. You sure that it would be an improvement to switch to that in a header that is usually (heh, let's assume use cases!;-) installed system-wide?3. As I said, I am wondering what good typedefs really do. Somehow, since we're wrapping stuff anyway, I wonder if the (since when? still reading …) standard
long longwouldn't be better, even. At least 64 bits, but possibly more on a crazy platform that does 128 bit offsets.4. Possibly. If we're not doing a fully new API, this point is moot. It would be
mpg123_enum_or_bitwise_combination_of_them;-) I think justintis darn practical there. Somehow an API that just uses basic types without any_tstuff gains appeal for me …5. Also, only relevant for a v2 API. Cannot just change things. But we can decide what to use for the read callback in the added portable
mpg123_replace_reader_handle()(maybe with a shorter name,mpg123_iosetup()?). The restricted range ofssize_treturn withsize_targument is already stupid. Could both be long, actually. You see, I'm getting a bit annoyed by a thousand names for a handful of basic types;-) But yes, long would be bad for Windows. I do like being able to drop in pointers to the system'sread()andlseek()on POSIX (or emulations thereof) …6. Careful there. Most places really are fine. For debug prints, there's
OFF_Pand the cast tooff_p, which can resort tolongifintmax_tis not there. You mean there are overflows in the casts tolongin that case? Or did you find places where the cast is missing? Using morelong longcan indeed ease things with%lldbeing usable. Thelongtype is not useless. It's for variables that are fine with 32 bits and should be implemented using the most convenient type for that on the current architecture. For computations, it can make a huge performance difference if you are throwing 32 bits or 64 bits around per number. I'd assumelongto be something sensible that maps to machine registers on a 32 bit system.7. Well, wishlist for a v2 API, but yes, all API exposed with
MPG123_PORTABLE_APIshall not be subject to the largefile renames. I'd have to keep the enum renames, though. You are not suggesting dropping those in favour of the possibly build-dependent enums?8. API version from header … you'd like to get away from a preprocessed header (.h.in to .h). I can somewhat understand that. Well, one could replace code in
configure.acto grep and cut them out of the headers.9. Only with a v2 API … and even then, too many numbers, for my taste. Actually,
mpg123v2prefix alone is an argument for me to not to do a separate API, from an aesthetic viewpoint;-)10. Same.
11. Ok, this is another can of worms. Actually, only on Windows does this matter at all. POSIX just doesn't care about the encoding of the binary blob handed to
open(). So we settled on everything being UTF-8 and added code to funnel wide characters in and out. The Windows build of mpg123 gets wide characters in argv, translates them to UTF-8,compat_open()translates back usingu2wlongpath(). Encoding sucks. So I'll take something that works when everything's ugly. In fact,mpg123the application isn't using plainmpg123_open()right now, onlympg123_open_fd()andmpg123_open_handle(). The extra toolsmpg123-id3dumpandmpg123-stripdo, as do examples, since it is a lot simpler than juggling with callbacks.It could be a separate issue to add a
mpg123_wopen()… but I'd fear to implement that right on POSIX where there is no underlyingwopen(). I'd have to decide which encoding to convert to for the current locale. I'd rather really not do that.12. hidden with portable API
13. my problem, internally
14. Except that the long names are annoying. But I do get your point. The header is a measure to avoid conflicts with non-static internal symbols for static linking. I'd prefer a world where that is not necessary. Maybe one could rework things to make more symbols local/static so that fewer of these ugly names are needed. But really, it's a separate issue for the future.
15. I covered that earlier. There is a github mirror. We could add CI there. Or elsewhere. A topic separate from the API.
16. Good.
Last edit: Thomas Orgis 2022-09-25
You got something to add?
I am sorry for the late reply.
If you want to keep all current ABI and API,
MPG123_PORTABLE_APImay be a way to go. I still suggest new symbol names for the new functions: The portable API functions would not rely onssize_t, but insteadptrdiff_t(or anything else that is actually available everywhere). As these types only somewhat guarantee the bit width and in particular not the exact type used (int/long/long long), a change here could cause a mismatch of declared and defined function type between the 2 APIs. I.e. you would not be able to use the same function implementations for both the old API and the portable API due to that anyway.There already is
mpg123_free(void*), sompg123_icy2utf8()is fine as is. See https://sourceforge.net/p/mpg123/bugs/276/, which is exactly the same issue that I was talking about. Documentation ofmpg123_icy2utf8()could be improved to mentionmpg123_free().ptrdiff_tis the only available type in the C standard that somewhat meets the requirements: 1. about the size ofsize_t, 2.signed. There is alsointptr_t, but that type is optional in the standard. For the old API, you need to include the non-standard POSIX header<sys/types.h>, however that must only happen for notMPT123_PORTABLE_API. Frankly, I do not like usingptrdiff_tasssize_tthat much either, it's just the closest we have got that is actually portable across all platforms. FWIW, I am not aware of a platform wheresizeof(ptrdiff_t) != sizeof(size_t), even though that would be allowed by the standard. But keeping that in mind, providing an easy way to use a different type via a simpletypedef ptrdiff_t mpg123_ssize_t;in the header is probably a good idea. As the only use ofssize_tis the reader API, getting rid of it completly and just usingint64_tmight also be an option. Another, arguably even better approach would be to just not overload a single return value with 2 different meanings (1. returned data amount, 2 error code) by e.g. returning a struct, or returning an error and using an out parameter for the returned data.I think you maybe somewhat missing the point here. The system-installed
mpg123.hwill catch the system-installed one with both<fmt123.h>or"fmt123.h". The local developmentmpg123.hwill currently always catch the system-installed<fmt123.h>. It would catch the local one with"fmt123.h". A local developmentmpg123.hshould better NOT catch the system-installed<fmt123.h>, because then you cannot ever develop an updatedfmt123.hwhen libmpg123 is installed.<>prefers the (system) include path.""preferes the local directory of the current file. Headers of the same project should always use public headers from the same project via the current directory, otherwise you do get version mismatch if another version of the project is installed. Adding-I.or whereever the relative path to a localfmt123.hwould be, works around this issue, however that in turn again poses additional requirements on the build system that just do not need to be there. This has actually bitten us when building libopenmpt with XCode (https://github.com/OpenMPT/openmpt/commit/c818518b0afe65a26f1b11829b6a9b5d1ce14515, I do not remember the precise cause here though; might have been a different order in which XCode appends/prepends project include paths to the compiler's set of system include paths, and/or some interaction with some include paths being-isystemand some overriding behaviour). I guess there would also be similar problems if you build multiple dependend projects with Autotools without installing the intermediate libraries system-wide (but I am not familiar with such build systems).With some non-existent 128bit platform, you will have to update the API and implementation anyway. There is absolutely no point in optimizing the API for non-existent platforms. Just use an ABI-forcing 64bit
int64_t. Otherwise, you absolutely will have the very same stupidoff_tissues withlong longin the future on 128bit platforms. Semantic typedefs could the API more readable. It is actually very helpful to be able to distinguish values in the API if they are clearly namedmpg123_off_t(local file offset) ormpg123_samplecount_t(sample offset). I do not have a strong opinion on that though, so justint64_twould also be fine. Also, 64bit is just enough, so there is nothing gained from planning for hypothetical 128bit file or sample offsets (63bit sample offsets allow for 6 million years at 48kHz, 63bit file offsets at 320kbps allow for even more).long longexists since C99 and C++11 (in practice also before C++11 as a non-standard extensions, when the same compiler also supported C99).Yeah,
intis fine I guess, as that is the type ofenumvalues in the C18 standard (that changed with C23, see https://thephd.dev/c23-is-coming-here-is-what-is-on-the-menu / https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3030.htm).Just reusing pointers to system functions will not work portably. Force-casting them to function pointers with different declared argument types is undefined behaviour. And, no, you cannot use
longhere at all. On LLP64,longis 32bit andsize_tis 64bit.sizeof(long)is unrelated to both,sizeof(int)andsizeof(size_t)when looking at a common subset of different platforms. There is no situation in a portable API to ever uselong. It makes no sense. Just usingint64_tfor file offsets and return values would be fine for me. I do not have any strong opinion about how functions are called, so renaming would be ok too.Yes, a lot of the debug printf do cast
off_ttolong, which is just wrong.long longwith%lldorint64_twithPRId64would avoid truncation on ILP32 platforms.longis not fine here, as it cannot represent 64bit values on all platforms. If you would want (which you do not, and I frankly cannot imagine any situation why anyone would ever want that such a type as optimizing compilers exist and we are not in the 80s any more) the "most convenient type of at lest N bits width", there isint_fastN_t;longis not the type you are looking for here. The only places where fundamental types make sense are in situations that they are used/specified by the standard directly (intforerrnoandenum, for example). There is no place wherelong(exceptfseek/ftell, which is broken anyway) is used exclusively in the standard.Yes, without also dropping the enum renames, this will IMHO again cause maintanence hassle in the future. It's just hard to use and unneccessarily difficult to read for users (you, as the author, are probably familiar with all the renames, but for me as a user they are just very much annoying and wasting time for absolutely no reason). Just mark the old not-to-be-used API deprecated, let the user explicitly call the new names. Yes, this will require users to change their code, but the major upside is that code will converge towards a state where all this trickery can be removed, instead of piling up even more trcikery basically forever.
That should not be too hard I guess:
grep MPG123_API_VERSION mpg123.h | awk '{print $3;}'. I do not think anything more fancy would be waranted here. However, getting rid of modifying the header also requires getting rid of the conditional largefile renaming, which, when you want to keep all that, might need a separate NEW headermpg123_portable.hfor the portable API. Applications would need to checkMPG123_API_VERSION(from the old header) in order to decide whethermpg123_portable.hwould be available though, andMPG123_PORTABLE_APIwould still be required to remove all non-portable things from the old header. However,mpg123.hwould still depend on the build system, and I absolutely hate that. So this does not work. What could maybe be possible is moving all renaming into a separatempg123_deprecated.hand including that frommpg123.honly if!MPG123_PORTABLE_API. That way,mpg123.hcould become static.Now, this might actually turn out to be a good first step in any case: grep the version from the header, move anything that is not portable into a separate header, and add
MPG123_PORTABLE_APIwhich disables inclusion of that header. After this first step,MPG123_PORTABLE_APIwould be dysfunctional as it is missing crucial functionality, but all of that can be added back later, as even now, code could setMPG123_PORTABLE_API, then checkMPG123_API_VERSIONand if that's too low, still#include <mpg123_deprecated.h>until the new portable API would be complete. I will explicitly state that I consider being able to detect and solve all these conditions solely in client code via the preprocessor is very important to me. Otherwise, this would need to induce logic into the build system of client code.From an aesthetic viewpoint, any preprocessor renaming of API names is also in the "disgusting as hell" department for me.
Renaming the library itself would be kind of necessary when breaking ABI though, as there otherwise would be no way to use the old and new one side-by-side in the same process (which is basically a requirement to allow for smooth transitioning).
Yeah, that is kind of a pet peeve of mine: There is absolutely no way to portably open a file without being aware and vary about encodings and string types. So, assuming the way forward would be some kind of
MPG123_PORTABLE_APIand keeping all current APIs, I suggest just also disablingmpg123_openand related functions forMPG123_PORTABLE_API. The correct portable way involves opening in client code and usingmpg123_replace_readeralready anyway.Agreed.
sure
14./15. Yeah, separate concerns.
Last edit: manx 2023-01-23
Comments on the prior of syn123 (only two off_t-using functions) in revision 5238? There's src/libsyn123/syn123.h now (no h.in) and
syn123_resample_total64()as explicitint64_tsymbol now, along with a(nother) switch toget rid ofoff_tAPI in the header, but still wrapper/alias definitions. On x86_64, I getThose all amount to the same functionality, but with differing prototypes. I'd need to do a 32 bit build, too, which should add a
_32one (and change what the suffix-less one is). On LFS-insensitive systems, you get the_64, anyway, to keep the header fixed. I hope BSD people are not too furious at that waste of bits.Diff:
Hm, this needs fixup for 32 bit platforms … I need to get rid of the largefile stuff in configure that turns
off_tinto 64 bits and use_LARGEFILE64_SOURCEinstead.Rev. 5240 now. Please don't fret too much about the
off_taliasing/wrapping, but focus on what you get withSYN123_PORTABLE_API.I/O stuff can be handled, turning non-portable
off_tAPI into wrappers over the new stuff. But for the portable case, there's some more functions that might need suffix-64 variants. So, all funcs withoff_tint them someplace:int mpg123_decode_frame( mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes );int mpg123_framebyframe_decode( mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes );off_t mpg123_framepos(mpg123_handle *mh);off_t mpg123_tell(mpg123_handle *mh);off_t mpg123_tellframe(mpg123_handle *mh);off_t mpg123_tell_stream(mpg123_handle *mh);off_t mpg123_seek( mpg123_handle *mh, off_t sampleoff, int whence );off_t mpg123_feedseek( mpg123_handle *mh, off_t sampleoff, int whence, off_t *input_offset );off_t mpg123_seek_frame( mpg123_handle *mh, off_t frameoff, int whence );off_t mpg123_timeframe(mpg123_handle *mh, double sec);int mpg123_index( mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill );int mpg123_set_index( mpg123_handle *mh, off_t *offsets, off_t step, size_t fill );int mpg123_position( mpg123_handle *mh, off_t frame_offset, off_t buffered_bytes, off_t *current_frame, off_t *frames_left, double *current_seconds, double *seconds_left);off_t mpg123_framelength(mpg123_handle *mh);off_t mpg123_length(mpg123_handle *mh);int mpg123_set_filesize(mpg123_handle *mh, off_t size);int mpg123_replace_reader( mpg123_handle *mh, mpg123_ssize_t (*r_read) (int, void *, size_t), off_t (*r_lseek)(int, off_t, int));int mpg123_replace_reader_handle( mpg123_handle *mh, mpg123_ssize_t (*r_read) (void *, void *, size_t), off_t (*r_lseek)(void *, off_t, int), void (*cleanup)(void*) );Not all of them need to be present in portable API. Obvious ones that are necessary are simple inquiry functions like
mpg123_tell,mpg123_tellframe.mpg123_positionis a relic, anyway, and should be replaced by code in the mpg123 main program doing the calculations. One thing that's a bit nasty ismpg123_index. It directly returns the pointer to the internal index array. If we were to dropoff_tfrom the build, this function would need to construct a fake buffer for that purpose to be able to offer theoff_tshim. Oh, dear. I just see that I did exactly that inlfs_wrap.calready. Meh, so deep in there already. Have to think if I continue to definempg123_index64. I guess I could, as the wrapper code already exists for inefficient handling of 32 bit conversion. I hope you don't look that close when I make the 64 bitoff_tvariant ofmpg123_indexjust cast the internalint64_tpointer tooff_t, the 32 bit one doing what it does now with the copy;-)One might add a more proper
mpg123_get_index64to mirrormpg123_set_index64, always copying the index and managing the user buffer, but I intend to make use of the fact that I am switching to an unambiguous type. and avoid the unnecessary copy of the buffer just to print it out in the mpg123 program (or store away to a file in other applications).Not sure if I'll include
framebyframe_decodein portable API. This was actually rather specific API for a previous project member's own player software. This is 1 of 18 functions, so no big difference.I wonder what functions I could omit from a 64 bit API. I could replace a number of position query functions with a single one with optional pointer arguments, but that's less usable than a plain
mpg123_tellframe64. Skipping parts doesn't really make sense for code that is contained in libmpg123, anyway (like the feeder buffer handling). Omitting certain stuff from the portable API would open the path for a trimmed-down libmpg123 build (optional) that actually removes code for the old API. But then, I do already carry configure switches for getting rid of code like that. A minimal build with only handle I/O with 64 bit integers will be available naturally, just not the default.So I guess the default build will just grow with 16 additional symbols (dropping
mpg123_positionand only adding one variant ofmpg123_replace_readersimply asmpg123_reader--- or asmpg123_iosetup, even if there is only I, not O):int mpg123_decode_frame64( mpg123_handle *mh, int64_t *num, unsigned char **audio, size_t *bytes );int mpg123_framebyframe_decode64( mpg123_handle *mh, int64_t *num, unsigned char **audio, size_t *bytes );int64_t mpg123_framepos64(mpg123_handle *mh);int64_t mpg123_tell64(mpg123_handle *mh);int64_t mpg123_tellframe64(mpg123_handle *mh);int64_t mpg123_tell_stream64(mpg123_handle *mh);int64_t mpg123_seek64( mpg123_handle *mh, int64_t sampleoff, int whence );int64_t mpg123_feedsee64k( mpg123_handle *mh, int64_t sampleoff, int whence, int_t *input_offset );int64_t mpg123_seek_frame64( mpg123_handle *mh, int64_t frameoff, int whence );int64_t mpg123_timeframe64(mpg123_handle *mh, double sec);int mpg123_index64( mpg123_handle *mh, int64_t **offsets, int64_t *step, size_t *fill );int mpg123_set_index64( mpg123_handle *mh, int64_t *offsets, int64_t step, size_t fill );int64_t mpg123_framelength64(mpg123_handle *mh);int64_t mpg123_length64(mpg123_handle *mh);int mpg123_set_filesize64(mpg123_handle *mh, int64_t size);int mpg123_reader( mpg123_handle *mh, int (*r_read) (void *, void *, size_t, size_t *), int64_t (*r_lseek)(void *, int64_t, int), void (*cleanup)(void*) );Would it make sense to rather name the last one
mpg123_reader64(ormpg123_iosetup64, ormpg123_stream_setup64… opinion about that?) for consistency? So that allint64_t-based functions have that suffix? Or try to coin new names altogether that don't conflict with the old ones, avoiding the explicit suffix, but deviating from some rather obvious names?sounds fine
Given the documentation already deprecates it, maybe make the source also deprecate it. Almost nobody reads documentation, but
__attribute__((deprecated))(and similar) will get noticed. There is of course no need to carry any deprecated function over to a new API.So, the old API leaks the off_t internal implementation detail to API users. For the new API, the internal table obviously needs to be 64bit anyway, so an emulation of the old API on top of that would need to store that copy somehere, which is unfortunate.
mpg123_get_index64sounds fine to me.It's documented as "experimental", thus not bringing it to the portable API sounds totally fine to me. If someone wants it, it can probably always be added later on. If the API is so much experimental that it should not be used at all, marking it deprecated might also make sense.
I do not have any real opinion on that one. There are valid arugments for single purpose functions, as well as for single functions querying all such info at once.
I like that! :D
list look ok at a first glance (there is a typo in mpg123_feedsee64k)
I do not have a strong opinion on
readervsreader64vsiosetup64. I really dislike calling (potentially) seekable things "stream" though (C++ also messed this one up).If the previous name was a good fit, I do not think changing the name makes much sense. So, suffixing "64" or "_2" or "_v2" would all work for me. If the previous name was rather awkward ("replace_reader_handle" comes to mind), a completely new name makes sense. I guess making them consistent, by also using the coosen suffix, would be helpful, but again, no strong opinion on that.
svn r5304 took a drastic action :
bad, IMO.
Yes MPG123_LARGENAME thing was, and still is, an abomination.
And mpg123_replace_reader also was, and still is, an abomination.
But if you are going to break things, just break things: Why not
just drop the old file i/o stuff and provide two simple methods:
One set with long offsets and one set with int64_t offsets, both
available in both 32 and 64 bit systems.
At the very least, provide the simplicity of libvorbis or opusfile
by adding, for e.g., a new mpg123_opencallbacks (with long offsets)
and a new mpg123_opencallbacks64 (with int64_t offsets) both being
available even with --enable-portable in effect so that mpg123_seek,
tell and friends can still be accessible.
I hoped to make everyone happy by both adding the portable API with fixed int64_t and keeping all old API paths working. The
--enable-portableswitch is only for people who want to do a stripped-down library build. You are free to ignore it. But: Where did you get the impression that there is no seek or tell functionality? There arempg123_seek64()andmpg123_tell64()(and friends). At least they should be.I took pains not to break anything. A default library build on x86 gives you
What is missing here? Any build with or without
_FILE_OFFSET_BITSshould just work and find its functions with 32 bit off_t or 64 bit off_t.Also, did you miss the addition of
mpg123_reader64()? Or what else do you mean withmpg123_opencallbacks64()?(I just noticed that I messed up the
O_LARGEFILEdetection … neutered the actual largefile opening on x86 kernels … will fix tomorrow.)Only mpg123_seek|tell64 are available in portable build, not mpg123_seek|tell, but OK I guess.
mpg123_reader64: I do seem to have missed that. You do mpg123_new(), then call mpg123_reader64 to set callbacks, yes?
The workflow is
mpg123_new();
mpg123_reader64();
mpg123_open_handle();
mpg123_seek64();
mpg123_tell64();
mpg123_read();
mpg123_close();
or you can continue to use the mpg123_open_feed() path, also withmpg123_tell64() and mpg123_feedseek64(), in that case.
But if you don't fancy the 64 suffix, nothing has to change. You just might have trouble representing sample offsets above 2 billion in your app, but libmpg123 will decode the large file.
Or would a
mpg123_open64(handle, readerfunc, seekfunc, cleanupfunc)make sense? I guess it would complicate things … and introducing ampg123_read64()andmpg123_close64()for consistency is maybe just wasting bits.Yep, got it
Nope, not necessary (not when old stuff is around.)
So … this is coming towards closure now. I'll prepare the current state of the changed API for release soon. Last chance to speak up.
After a long time … 1.32 offers this. Some minor cleanup will follow.