Generic-user-small Alain O'Dea 18 posts

The SHOUTcast server example uses the mp3_manager module. This module is not described in the book and its code is not provided in the book. The code from the site includes mp3_manager.erl, but it includes hard-coded paths for Joe’s own computer.

How does the mp3_manager module work and what needs to be changed to make it work on Mac OS X?

 
Generic-user-small Alain O'Dea 18 posts

I added a function start/0 to mp3_manager.erl to support a configuration file called mp3_manager. The format of the config file is {Root, Pattern}.:

mp3_manager.erl:

start() ->
    {ok,[{Root, Pattern}|_]} = file:consult(mp3_manager),
    Files = lib_files_find:files(Root, Pattern, true),
    V = map(fun handle/1, Files),
    lib_misc:dump("mp3data", V).

mp3_manager:

{"/Users/alain/Music/iTunes/iTunes Music", "*.mp3"}.

I noticed after I ran the modified mp3_manager module that it creates a file called mp3data.tmp instead of just mp3data as the shout module expects. For some reason lib_misc:dump/2 appends .tmp to the filename passed into it before writing.

lib_misc will need to be modified not to append .tmp or the dumped file will have to be renamed to allow the SHOUTcast server to start.

 
Generic-user-small Alain O'Dea 18 posts

Certain MP3 files will cause the shout module to log an error. In the mp3data file they show up with format {File,no} instead of the expected {File, {_Tag, Info}}. This seems to be because mp3_manager:parse_start_tag/1 only reads ID3 tags.

Here is a simple solution. Refactor and extend shout:unpack_song_descriptor/1 as follows:

unpack_song_descriptor({File, Metadata}) ->
    PrintStr = get_print_str(Metadata),
    L1 = ["StreamTitle='", PrintStr,
          "';StreamUrl='http://localhost:3000';"],
    %% io:format("L1=~p~n", [L1]),
    Bin = list_to_binary(L1),
    Nblocks = ((size(Bin) - 1) div 16) + 1,
    NPad = Nblocks*16 - size(Bin),
    Extra = lists:duplicate(NPad, 0),
    Header = list_to_binary([Nblocks, Bin, Extra]),
    %% Header is the SHOUTcast header
    {File, PrintStr, Header}.

get_print_str({_Tag, Info}) ->
    list_to_binary(make_header1(Info));
get_print_str(no) ->
    <<"UNKNOWN">>.

This makes shout:unpack_song_descriptor/1 tolerant of incomplete metadata extraction from mp3_manager and allows the SHOUTcast server to play songs with broken ID3 tags or non-ID3 tags. I love how straight-forward refactoring is in Erlang.

 
3_small_small Joe Armstrong 5 posts

Excellent. The reason for dumping to a .tmp file was that I sometimes manually removed
some files before renaming to mp3data.

Unfortunately it proved to be rather difficult to write code that correct unpacks all ID3 tags
these can be at the start or end of the file – and some of them seem to have been written by buggy programs so the tags are not according to the standards. Correctly parsing all possible
tags might make a nice project. The code in the book should give you some ideas as how to start this.

Incidentally, I was able to make the shoutcast code in the book run with my soundbridge so I could
remotely control the soundbrideg – If I had more time I’d persue this more….

Cheers

/Joe Armstrng

4 posts, 2 voices