For the purposes of improving the direction of Uniaud development, I am proposing the following course. Note that this is not implemented or even certain. I am posting it to receive feedback, refinement, and hopefully approval from the rest of the development team.
I. 1.1.4GA Milestone
We might sometimes ask ourselves why we still have 1.1.4 in trunk. It is my opinion that we need to have a stable release. By stable, of course I do not mean bug-free. I mean a modicum of stability, defined narrowly as: no known regressions, and builds cleanly, easily, and predictably. Once this is met, 1.1.4GA can be released, and the Uniaud32 code that is now trunk should become the 1.1.x branch, as Paul suggested. It then is possible, if someone is so inclined, to apply bugfixes to it, so there could be a 1.1.5, 1.1.6, etc. purely with bugfixes. I think it should be there, with this potentiality, for the sake of stable support, even though I personally doubt there will be any interest in pursuing it, because of my optimism about Uniaud 2.0.
I advocate releasing 1.1.4GA first, so that we do have a stable release. We may consider moving it now, and skipping the GA release, but I do not favor this option because it says:
- The code is stable now, when it is not (though it's now mostly there!).
- It doesn't matter whether we ever have a stable release, when I think we believe it does, or
- The 2.0 branch is so much better than current trunk. This is largely true, but most of the remaining open tickets on the 1.1.4GA Milestone apply also to 2.0, so it makes sense to finish this stabilization right away, and move it to a branch as an act of declaring the codebase we inherited stabilized, as a foundation for future development.
II. Resync Effort
The stated original goal of "resync"-ing the code was to bring us up to the latest ALSA. We all recognized right away how important it is to be able to make use of current ALSA code, and to have a strategy for remaining current going forward. Two methods were ultimately employed, and one essentially achieved that goal, albeit with some hardware support still lacking. It is time, then, to re-assess. Here I contrast the results of the two methods and draw conclusions for planning future action.
A. The "Merge Method" == I have employed uses 'svn merge' to update the existing ALSA code, which we identified as a range of old versions, one version at a time, beginning with the oldest, preserving any modifications.
This turned out to be a very slow process, and ended up causing delays in development. Whatever value we may attribute to this work, the fact that I have monopolized it, and taken so long with it, has done harm to the project. We have delayed work that might otherwise have been done sooner, because of optimism about the expected results, and underestimating the time it would take.
Future strategies should avoid serializing development behind a task that one person is doing, and as much as possible, avoid allowing one person to take possession of a task to the extent that it interferes with what others might want to accomplish.
The second shortcoming of this method is that although it has exposed the inconsistency and disorder of Uniaud's ALSA code, it has not, as yet, quantified it. I cannot tell you how much it diverges from ALSA, or how many files contain mixed versions. I can just anecdotally say it's bad, but little by little getting better. Interesting, but not useful.
As I see it, the work in the "alsa-resync1" branch is the only way to quantify the existing state of Uniaud's "legacy" ALSA code. This quantification is the only remaining benefit of this branch, so that should be its only objective. So I propose a new strategy.
First, I will identify all files which are not being used in the build and are identical to some version of ALSA. As they therefore have no value, I will remove them, to reduce the number of files I'm dealing with.
Secondly, in the process of merging, I will classify the files. They can be
- identical to ALSA,
- matching a version of ALSA but with modification, or
- not identifiable as any particular version of ALSA.
An appropriate mechanism for representing the classifications could be the 'svn propset' command, to label them in the repo itself.
Once this is complete, at the least, it will give some numerical data about it, so that will help us make a decision about how to proceed. It also means that those files that are marked as modified can be used to create patches, which will let us make judgments about them, and to then possibly use them with later versions of ALSA.
B. The "Drop In" Method == Paul employed simply replaced the ALSA code with the latest, and fixed it so it would compile. This turned out to work very quickly, and it has produced good results. It uses the latest and best ALSA code available, and it is absent the complications and confusion caused by so many mixed versions.
What is lost from the old code with this method is a big unknown. It is possible we will not miss it. This is where the revised process on alsa-resync1 branch can fill in the gaps, at least revealing it so we can decide.
Looking forward to future upgrades, this method, as currently structured, does have one weakness, that if a portion of the code does not port easily, some hardware (or feature, or whatever) could go unsupported while we work it out. So potentially Uniaud could sometimes support a device, and sometimes not, depending on where we are with the porting process on the latest version. We may not even finish one version before the next comes out. So users have to educate themselves on which versons of Uniaud supports a device, and check the status of it before they go to download.
I would suggest this as an hypothetical, but the current lack of SB Live support proves this can happen. The reason for this isn't lack of effort, it's simply the rigidity of requiring all code to be the same version. It is reasonable for these sorts of things to occasionally be delayed. While the port of the latest code is in progress, if the older code were preserved, in most cases, so would the existing functionality.
We have spent a lot of time fussing with ALSA, while the rest of its components require attention. The primary reason for using ALSA is to let the ALSA project handle hardware support, to reduce the maintenance burden on Uniaud. Not to create one.
For that reason, both the "Merge Method" and the "Drop In Method," as they stand, still require more of us than they should. With either one, every time ALSA puts out a release, we have to then scramble to merge it or re-port it, checking what was done before. This means we are always spending time working on ALSA instead of other things, and we are always lagging behind the latest release of ALSA.
III. The Solution
We need a solution that minimizes the effort required to remain current with ALSA. But more than that, we need to define clearly where Uniaud ends and ALSA begins, so that we only maintain Uniaud. (No more forking.) Perhaps most importantly, we need these definitions to be clear enough that if we all quit and someone else looks at it, he can understand exactly what the status is and what to do.
So to end the complications it causes, I propose removing the ALSA code from the Uniaud repository. Rather than storing an edited copy of ALSA to designate the changes Uniaud requires, we should instead store patches.
That might seem awkward at first glance, but ALSA does it for their alsa-driver package, and as a rule, anything ALSA does means it's OK for Uniaud. Bear with me on this while I explain.
Briefly, ALSA has two editions, alsa-kernel and alsa-driver. Alsa-kernel is the ALSA code as it exists in the Linux kernel. Alsa-driver they distribute separately. You have the option of building your kernel without ALSA, and then using the alsa-driver package for your sound support. This generally makes it easier to stay current with ALSA, and it also means you can use the latest ALSA with older kernels.
Alsa-driver includes a snapshot of alsa-kernel, and a set of patches. The make process automatically applies the patches when it builds. I do not yet know how they handle them in development, but I would guess they have some scripts we could use.
So I want to change Uniaud so that it builds exactly the same way as alsa-driver, but with some enhancements.
To see the benefit, let's play this out. Let's say hypothetically that we had this ready now, and ALSA 1.0.18 is released. We download the src package and untar it in our ALSA directory, which is defined in Makefile.inc. This directory contains all the ALSA versions we might want, in their own subdirectories. Now, in our Uniaud32 working directory, we run:
wmake UNI_ALSA_VERSION=1.0.18
This overrides the default ALSA version, which right now would be 1.0.17, and uses the 1.0.18 code, automatically applying all our patches.
OK, now let's say the build fails, because of an error in trident_main.c. Well, we're not that interested in Trident today, and all reports say they work fine in 1.0.17, so we just edit Uniaud's trident_main file to force it to version 1.0.17, and recompile. It grabs that file instead from 1.0.17, and the rest from 1.0.18.
Do this for a few more errors, and then it finishes, and we have an updated Uniaud32. Not completely updated, but see what we've done. In very little time, we know exactly how well 1.0.18 integrates with our existing code, and we have progress on an update. We have mixed versions, but it is exceedingly easy to find out what version of each file we are using without even looking at the ALSA code, so it isn't really a problem. We could conceivably mix several versions. As long as it works, and we know what version, and we don't have to look at the code, why not?
We can even commit it at this point, because 1.0.17 was the last supported version, and we haven't actually changed the default to 1.0.18.
Now sometime later we're in a compile-fixing mood, so we run:
wmake UNI_FORCE_ALSA_VERSION=1.0.18
Now everywhere that a version is set in a file, it will be overridden to use 1.0.18, and we can go about trying to port the rest of ALSA 1.0.18.
In the meantime, we still have a working driver for all supported hardware, with the latest Uniaud code. No temporarily dropped support, no waiting for anyone to finish, no pressure, no blame. All updates are good, even partial ones. The remaining portion of the updates can be done whenever someone feels like doing it, or if it actually proves to be a problem.
Let's talk a little bit about our patches. The patches from Paul's work are easy, because they are against ALSA 1.0.17. But, are they against alsa-driver or alsa-kernel? As I understand, he used some alsa-driver patches. Let's keep this simple. Alsa-driver patches are ALSA code, not Uniaud code. Where a file should be alsa-driver, we just set ALSA_DRIVER for that file in Uniaud, and it will add the patch from alsa-driver, in addition to any other patch we have. This is important, so that we do not have to keep going back to the alsa-driver patches to update our own, or figure out which are ours and which are from alsa-driver.
The next question is, should we just always use alsa-driver patches then for everything? I don't know. Let's try it:
wmake ALSA_DRIVER=1
Decide based on that. Compare this with how we would figure that out in the current setup. I don't think any of us would want to bother with the work.
Any patches that result from alsa-resync1, as they become ready, I'm going to call legacy patches, and make them optional, but on by default. The reason is that in testing we may find some problem and think, "I'll bet it's that old stuff Brendan threw in." So, build with
wmake UNI_LEGACY_PATCHES=0
and see if it goes away. Then you know where to look, or not look.
One last use case that is important.
To remain current, waiting around for releases to get updates doesn't necessarily make sense. To be ready for 1.0.19, we probably want to start experimenting with it ahead of time. There is no harm in snapshot drops, because we have no ALSA code of our own to pollute. So, we could even build daily with
wmake UNI_ALSA_VERSION=git
All we have to do is have a subdirectory in our ALSA directory called alsa-driver-git, with the latest drop. If we find a compile problem or something else we need to fix, we can do it and re-test with the default version before committing. No problem.
Hopefully you are now persuaded that this ease of working with different ALSA versions more than compensates for the little extra effort required for maintaining patches in the repo, even if we had to do it manually.
The LiveCD I described at Warpstock is outside the scope of this proposal, and it won't be done until after this is implemented, but it is worth mentioning as a side note that the mixed version "problem" and the LiveCD go together. If we suspect that mixed versions are causing an issue, we can use the LiveCD to easily test the same set of code under Linux and compare. This also applies to the other make options. ALSA could be tested under Linux with and without the Uniaud patches, with and without the legacy patches, etc.
IV. Deployment
One benefit that might be apparent is that this scheme lends itself well to a division of labor. One person can be testing with the latest drop from git, another porting the latest ALSA release, another adding more device support, another chasing bugs, etc., all without interfering with each other, and without waiting for someone else to finish something first. We can try all sorts of things with a common codebase, so that efforts are not dispersed across multiple branches, and we do not need to maintain multiple source trees on our local PC's.
So this is a good way to rein in our multiple branches and get down to just one set of source. This is why I want to get 1.1.4GA done asap and out of the way. That's where I'll be focusing primarily until that's done. Of course, most of the remaining tickets for 1.1.4GA are things anyone could do, so although they are not very exciting, anyone eager to see it done could help.
Initially I was thinking of making the new trunk a combination of the new build system, the non-ALSA code from uniaud32-2.0, with the new build setup, no alsa-kernel, and patches generated from alsa-resync1 and 2.0. But trying to do it all in one move can generate the serialization of arbitrary dependencies mentioned in Section II.A which causes unnecessary delays.
So this will be the end-goal, but we'll apply it a little at a time. Uniaud32-2.0 will be merged with trunk after 1.1.4GA, and I'll start on the new build system, as a make option until it is ready, so we still have working code in the meantime, and no other efforts or goals are interfered with. Once we're happy with it we'll finalize the patches and make the switch, removing the alsa-kernel code. The spec is defined, and we can refine the details, so anyone else who is enthusiastic about this new build system can contribute; it doesn't have to just be me.
I'm thinking of doing it by simply porting the makefiles as-is from alsa-driver to wmake, and then adding the capabilities I demo'ed in Section III.
Pending the port of the emu10k1 code from 1.0.17, we should probably keep the old version in the meantime, so that it isn't excluded.
I'll take responsibility for generating the legacy patches from alsa-resync1. It should be easier than continuing to merge endlessly, although it may take some more merges to accomplish it. The important thing is to not make anything dependent on it, so it isn't holding anything up, so they may even roll in after the 2.0 release. Once I generate some stats on the classifications of the files, we can make a decision about how important it is and what we want to do with it.
V. Conclusion
So with all this I am trying to cover all the bases:
- To transition from the old to the next generation of Uniaud32 code.
- To preserve the benefits of the work of both ALSA "resync" methods, while compensating for their respective deficiencies.
- To reduce the time needed to chase future updates from ALSA, while maximizing their benefit and accessibility.
- To eliminate the real and potential confusion and hassle of keeping a copy of ALSA as part of the code.
- Sensibly move to a single codebase so we truly have a 'Universal' driver.
- Lay the groundwork for the test LiveCD
- End the waiting and tooth-gnashing in alsa-resync1
Best of all, I think it should help make it a lot easier to concentrate on the real problems with Uniaud, and to spot where they are coming from.
I am eager to receive feedback on uniaud-dev about all this.
-Brendan