alsa.audio: add additional read cycle if there is more than 20ms space in buffer
[AROS.git] / workbench / devs / AHI / Drivers / Alsa / alsa-playslave.c
blobef782312aeaded399c90bf1b745f9e01ebad5589
1 /*
2 Copyright © 2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <aros/debug.h>
7 #include <config.h>
9 #include <devices/ahi.h>
10 #include <exec/execbase.h>
11 #include <libraries/ahi_sub.h>
13 #include "DriverData.h"
14 #include "library.h"
16 #include "alsa-bridge/alsa.h"
18 #define dd ((struct AlsaData*) AudioCtrl->ahiac_DriverData)
20 #define min(a,b) ( (a) < (b) ? (a) : (b) )
22 /******************************************************************************
23 ** The slave process **********************************************************
24 ******************************************************************************/
26 #undef SysBase
28 void Slave( struct ExecBase* SysBase );
30 #include <aros/asmcall.h>
32 AROS_UFH3(LONG, SlaveEntry,
33 AROS_UFHA(STRPTR, argPtr, A0),
34 AROS_UFHA(ULONG, argSize, D0),
35 AROS_UFHA(struct ExecBase *, SysBase, A6))
37 AROS_USERFUNC_INIT
38 Slave( SysBase );
39 AROS_USERFUNC_EXIT
42 #include <hardware/intbits.h>
43 #include <proto/timer.h>
45 AROS_INTH1(AHITimerTickCode, struct Task *, task)
47 AROS_INTFUNC_INIT
48 Signal(task, SIGBREAKF_CTRL_F);
49 return 0;
51 AROS_INTFUNC_EXIT
56 static void SmallDelay(struct ExecBase *SysBase)
58 struct Interrupt i;
60 i.is_Code = (APTR)AHITimerTickCode;
61 i.is_Data = FindTask(0);
62 i.is_Node.ln_Name = "AROS AHI Driver Timer Tick Server";
63 i.is_Node.ln_Pri = 0;
64 i.is_Node.ln_Type = NT_INTERRUPT;
66 SetSignal(0, SIGBREAKF_CTRL_F);
67 AddIntServer(INTB_VERTB, &i);
68 Wait(SIGBREAKF_CTRL_F);
69 RemIntServer(INTB_VERTB, &i);
72 void
73 Slave( struct ExecBase* SysBase )
75 struct AHIAudioCtrlDrv* AudioCtrl;
76 struct DriverBase* AHIsubBase;
77 struct AlsaBase* AlsaBase;
78 BOOL running;
79 ULONG signals;
80 LONG framesready = 0;
81 APTR framesptr = NULL;
83 AudioCtrl = (struct AHIAudioCtrlDrv*) FindTask(NULL)->tc_UserData;
84 AHIsubBase = (struct DriverBase*) dd->ahisubbase;
85 AlsaBase = (struct AlsaBase*) AHIsubBase;
87 dd->slavesignal = AllocSignal( -1 );
89 if( dd->slavesignal != -1 )
91 // Everything set up. Tell Master we're alive and healthy.
93 Signal( (struct Task*) dd->mastertask,
94 1L << dd->mastersignal );
96 running = TRUE;
98 while( running )
100 signals = SetSignal(0L,0L);
102 if( signals & ( SIGBREAKF_CTRL_C | (1L << dd->slavesignal) ) )
104 running = FALSE;
106 else
108 LONG framesfree = 0;
109 LONG readcycles = 0;
111 while(TRUE)
113 framesfree = ALSA_Avail(dd->alsahandle);
114 if (framesfree == ALSA_XRUN)
116 D(bug("[Alsa] ALSA_Avail() == XRUN\n"));
117 ALSA_Prepare(dd->alsahandle);
118 framesfree = ALSA_Avail(dd->alsahandle);
121 if (framesfree >= 64)
123 readcycles++;
124 if (framesfree >= AudioCtrl->ahiac_BuffSamples)
125 readcycles++;
126 break;
129 SmallDelay(SysBase);
132 /* Loop until alsa buffer is filled */
133 while (framesfree > 0)
135 LONG written;
137 if (framesready == 0)
139 if (readcycles == 0)
140 break;
142 CallHookPkt(AudioCtrl->ahiac_PlayerFunc, AudioCtrl, NULL );
143 CallHookPkt(AudioCtrl->ahiac_MixerFunc, AudioCtrl, dd->mixbuffer );
144 framesready = AudioCtrl->ahiac_BuffSamples;
145 framesptr = dd->mixbuffer;
146 readcycles--;
149 written = ALSA_Write(dd->alsahandle, framesptr, min(framesready,
150 framesfree));
151 if (written == ALSA_XRUN)
153 D(bug("[Alsa] ALSA_Write() == XRUN %d, %d\n", framesfree, framesready));
154 ALSA_Prepare(dd->alsahandle);
155 written = ALSA_Write(dd->alsahandle, framesptr, min(framesready,
156 framesfree));
159 framesready -= written;
160 framesfree -= written;
161 framesptr += written * 4;
163 CallHookA(AudioCtrl->ahiac_PostTimerFunc, (Object*) AudioCtrl, 0);
169 FreeSignal( dd->slavesignal );
170 dd->slavesignal = -1;
172 Forbid();
174 // Tell the Master we're dying
176 Signal( (struct Task*) dd->mastertask, 1L << dd->mastersignal );
178 dd->slavetask = NULL;
180 // Multitaking will resume when we are dead.