How should it work?


mixer says: create a device
mixer says: load()
mixer says: play()

1. Creation of device, meaning starting of decoder process, can take time and can fail.
2. Loading of a file can take time and can fail.
3. play() should be immediately do its work, decoder running, all set up: Just do the number crunching.

Further: seeking; can definetely take time.

Non-critical: setting of EQ.

All in all it would be nice when the socketeer gets the success info from the one who is responsible for success without halting the mixer. The mixer should only trigger the action and should not have to wait for it to complete. 
The creation of a new decoder may be an exception; the channels are mixer data. Mixer works with them. No sane way of delaying this.
Different with loading of files and seeking (!), ormally, this is in preparation for the next track due to play in some minutes (at least several seconds). We have tiiiiiiiiime...

So, trigger load(), give it a semaphore for the socketeer. 
Problem load() itself doesn't know when or even if the loading was successful. backwatch() knows this. At some time. load() has to wait for some (positive) sign from the backwatch(), then; after that sending a positive (or negative) sign to the socketeer and setting the state of the input accordingly. It's all about synchronisation. 

mpg123's responses:




Control interface to generic frontends
written/copyrights 1997/99 by Andreas Neuhaus (and Michael Hipp)

The generic remote interface allows frontends to easily control
mpg123 by commands through stdin/stdout. To start the generic
remote interface, start mpg123 with parameter -R.

As an example it's used by IRMP3, a tool that allows you to
control mpg123 with a standard infrared remote control. See
http://www.fasta.fh-dortmund.de/users/andy/irmp3/ for more
information.


COMMAND CODES
-------------

Command codes may be abbreviated by its first character.

QUIT
			Stop playing and quit player

LOAD <a>
			Load and play a file/URL.

STOP
			Stop playing (without quitting the player)

PAUSE
			Pause/unpause playing

JUMP [+|-]<a>
			Skip <a> frames:
			+32	forward 32 frames
			-32	rewind 32 frames
			0	jump to the beginning
			1024	jump to frame 1024


RESPONSE CODES
--------------

Note: mpg123 returns errors on stderr, so your frontend should
      look not only at stdout but also at stderr for responses.

@R MPG123
			Startup version message

@I ID3:<a><b><c>
			Status message after loading a song (ID3 song info)
			a = title (exactly 30 chars)
			b = artist (exactly 30 chars)
			c = album (exactly 30 chars)
			d = year (exactly 4 chars)
			e = comment (exactly 30 chars)
			f = genre (string)

@I <a>
			Status message after loading a song (no ID3 song info)
			a = filename without path and extension

@S <a> <b> <c> <d> <e> <f> <g> <h> <i> <j> <k> <l>
			Status message after loading a song (stream info)
			a = mpeg type (string)
			b = layer (int)
			c = sampling frequency (int)
			d = mode (string)
			e = mode extension (int)
			f = framesize (int)
			g = stereo (int)
			h = copyright (int)
			i = error protection (int)
			j = emphasis (int)
			k = bitrate (int)
			l = extension (int)

@F <a> <b> <c> <d>
			Status message during playing (frame info)
			a = framecount (int)
			b = frames left this song (int)
			c = seconds (float)
			d = seconds left (float)

@P <a>
			Playing status
			a = 0: playing stopped
			a = 1: playing paused
			a = 2: playing unpaused
ThOr: Not right; @P 1 comes on load... or did I do that? Corrected now: Always on playback start it says "@P 2" now.


@E <a>
			An error occured
			Errors may be also reported by mpg123 through
			stderr (without @E)
			a = error message (string)


also there is a "@1.000000" at start... and the obvious "Junk at beginning"

and the eq... I'm using my seq command, which results in 

@bass: <num> mid: <num> treble: <num>



Let's conclude:

I start the decoder. Backwatch looks for "@R MPG123" -> input ready (im_ready = true)

I want to load a file, load() gets called.
load() does: check if file exists and is readable (since mpg123 dies otherwise); wait for ok from backwatch (backwatch: see "@P 2" and sem_post(decoderplaysem) )

Same for jump...


Scenario:
	socketeer gets command, it creates an action 
	...waits for the semaphore...
	mixer calls the method
	the method talks to mpg123, returns
	mixer is there again...
	...and again...
	...
	backwatch gets the answer and triggers the semaphore for the socketeer
	socketeer awakes, gives response (positive/negative?) and is ready for next command
	
	
How to have the right semaphore for some backwatch event handy? Have a queue of commands that are in process with semaphore/errcode/retval attached (smells like struct, eh?), p.ex. load() locks, gives the command to mpg123 and adds the command to the queue. Release lock. Backwatch now gets some event (@J)

Now it's getting interesting. I'll have to empty the pipe on _every_ seel because I want either the right sound whenI start playback again and/or I need an accurate position.

The work:

pause ( seek() ) -  wait for confirmation ( backwatch() )
read until pipe empty ( readily() )
jump ( readily() ) - wait for confirmation, signal and return to socketeer ( backwatch() )

This makes quite a heap of communication. I wanted it multithreaded...

Just a note: Have in mind that when mpg123 has finished a file it is finished for mpg123... and it doesn't give a right result when the jump is too far... just replies with success and gives a "@P 0" afterwards... the unpause check of backwatch should look out.



This stuff works so far, maybe in a similar fashion. But most likely different because I update the code more often that the NOTES.

Now the top issue is SILENCE. Let's repeat it:

Silence
-------

I want to skip silence at beginning and at end, in a configurable way with reasonable default. That would be maybe 2 frames at most. Normally it should be at most one frame, though. But maybe it went wrong on cd mastering already... so try up to 2 frames of silence.
That's very straight forward on the beginning but means I need some preknowledge on the end. When I take 2 silent frames into account, I'll have to know the 2 frames and if they are the last.
As long as I use this feature only for "repairing" mp3s, I just need to have buffers of a frame's size... 

[some investigations]

It looks like it is one frame silence at start because of LAME tag and always _about_ 1152 samples junk because of mpg123.
So: 
- at 0: always ignore 1152 samples (junk from seek or LAME tag), the search for sound in the next 2304 samples (1 frame from mpg123/LAME and some safety buffer because of audio padding on cd or such stuff)
- at end: be sure to know the end 1152 samples in advance. always.



The internal communication
--------------------------

We have a list of pending commands called "cs", the data type is "commsemal", consisting of a type value and a comm_data pointer. 
A comm_data consits of an unsigned char error code, a semaphore, a double return value, a long return value and a thread that is attached. This thread is only important for mixer in order to properly kill a thread that wants itself to die.

all _real_ actions are governed by readily, the class methods only prepare the environment and wake the readily thread.
That means the readata sruct needs a field for the external comm_data to properly give return value and wake the waiting socketeer/mixer

methods:


load
	- fail if readily busy
	- set readily busy
	- delete any pending actions from watchlist
		maybe in future: look if external actions still pending, set error code and wake the external waiter...
	- set rd.cd
	- rd.action = LOAD
	- wake readily
	
(sample)seek
	- do nothing if position already reached
	- fail if readily busy
	- set readily busy
	- set rd.cd
	- rd.action = SEEK
	- wake readily
		
play
	- fail if readily busy
	- set readily busy
	- create rd.cd with playsem and misuse long return value for wanted samples
	- rd.action = PLAY
	- wake readily
	
set_eq 
	- if online and track playing and ...
		- add SEQ action to watch list
		- send SEQ command
	- otherwise: ?

should be triggered by input channel variable as eq...
skip_silence
	- only sets internal variable to activate the prebuffer/silence skip routines


readily actions

LOAD
	- NOT push a PAUSE to waitlist
	- order PAUSE
	- clear pipe (maybe with more sched_yield() than normally)
	- check if decoder_paused (otherwise something bad happened... on_line = false, waiting to be deleted)
	- send LOAD
	- wait for success
	- ignore first 1152 samples
	- empty prebuffer (set pos and fill to 0... )
	- if skip_silence: fill prebuffer else: delete buffer if still there
	- wake the waitress	

SEEK
	- if skip_silence - seek_buffered()
		- if wanted stuff already in buffer
			- advance prebuffer position, refill prebuffer 
	  	else
	    - clear buffer
			- if end_in_buffer:
			  - if seek aim is _before_ the now visible end
				  - order PAUSE, clear pipe order LOAD, wait
					else 
					- at_end = true; set position; set errcode; wake waitress; return <<============ !!!!!!!!!!!!!!!!!! 
			- order PAUSE, clear pipe, order JUMP, wait, ignore 1152 samples, fill prebuffer
	  else
	  - if near_end: make a LOAD first
	  - order PAUSE, clear pipe, order JUMP, wait, ignore 1152 samples
	- wake the waitress	



PLAY
	- wake the waitress	



...bah... update: I'll drop the buffer or nobuffer decision for now. Just using the buffer. Too complicated otherwise.
