From c61600bfdda6608feb6a390d20e2e1200afe93f6 Mon Sep 17 00:00:00 2001
From: tobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c>
Date: Fri, 30 Apr 2010 13:49:10 +0000
Subject: portaudio playback (not used by default) segfault fixed

git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2321 b956fd51-792f-4845-bead-9b4dfca2ff2c
---
 src/media/UAudioCore_Portaudio.pas     | 56 ++++++++++++++++++++++++++++++++++
 src/media/UAudioInput_Portaudio.pas    | 15 +++------
 src/media/UAudioPlayback_Portaudio.pas | 22 ++++++-------
 3 files changed, 71 insertions(+), 22 deletions(-)

diff --git a/src/media/UAudioCore_Portaudio.pas b/src/media/UAudioCore_Portaudio.pas
index 1c7e3ef5..c97b5d10 100644
--- a/src/media/UAudioCore_Portaudio.pas
+++ b/src/media/UAudioCore_Portaudio.pas
@@ -40,9 +40,13 @@ uses
 
 type
   TAudioCore_Portaudio = class
+    private
+      InitCount: integer; ///< keeps track of the number of Initialize/Terminate calls
     public
       constructor Create();
       class function GetInstance(): TAudioCore_Portaudio;
+      function Initialize(): boolean;
+      function Terminate(): boolean;
       function GetPreferredApiIndex(): TPaHostApiIndex;
       function TestDevice(inParams, outParams: PPaStreamParameters; var sampleRate: double): boolean;
   end;
@@ -92,6 +96,7 @@ var
 constructor TAudioCore_Portaudio.Create();
 begin
   inherited;
+  InitCount := 0;
 end;
 
 class function TAudioCore_Portaudio.GetInstance(): TAudioCore_Portaudio;
@@ -101,6 +106,57 @@ begin
   Result := Instance;
 end;
 
+function TAudioCore_Portaudio.Initialize(): boolean;
+var
+  Err: TPaError;
+begin
+  // initialize only once
+  if (InitCount > 0) then
+  begin
+    Inc(InitCount);
+    Result := true;
+    Exit;
+  end;
+
+  // init Portaudio
+  Err := Pa_Initialize();
+  if (Err <> paNoError) then
+  begin
+    Log.LogError(Pa_GetErrorText(Err), 'TAudioCore_Portaudio.Initialize');
+    Result := false;
+    Exit;
+  end;
+
+  // only increment on success
+  Inc(InitCount);
+  Result := true;
+end;
+
+function TAudioCore_Portaudio.Terminate(): boolean;
+var
+  Err: TPaError;
+begin
+  // decrement usage count
+  Dec(InitCount);
+  if (InitCount > 0) then
+  begin
+    // do not terminate yet
+    Result := true;
+    Exit;
+  end;
+
+  // terminate if usage count is 0
+  Err := Pa_Terminate();
+  if (Err <> paNoError) then
+  begin
+    Log.LogError(Pa_GetErrorText(Err), 'TAudioCore_Portaudio.Terminate');
+    Result := false;
+    Exit;
+  end;
+
+  Result := true;
+end;
+
 function TAudioCore_Portaudio.GetPreferredApiIndex(): TPaHostApiIndex;
 var
   i:        integer;
diff --git a/src/media/UAudioInput_Portaudio.pas b/src/media/UAudioInput_Portaudio.pas
index 92e549ff..c7364eb4 100644
--- a/src/media/UAudioInput_Portaudio.pas
+++ b/src/media/UAudioInput_Portaudio.pas
@@ -492,27 +492,20 @@ begin
 end;
 
 function TAudioInput_Portaudio.InitializeRecord(): boolean;
-var
-  err: TPaError;
 begin
+  Result := false;
   AudioCore := TAudioCore_Portaudio.GetInstance();
 
   // initialize portaudio
-  err := Pa_Initialize();
-  if (err <> paNoError) then
-  begin
-    Log.LogError(Pa_GetErrorText(err), 'TAudioInput_Portaudio.InitializeRecord');
-    Result := false;
-    Exit;
-  end;
-
+  if (not AudioCore.Initialize()) then
+     Exit;
   Result := EnumDevices();
 end;
 
 function TAudioInput_Portaudio.FinalizeRecord: boolean;
 begin
   CaptureStop;
-  Pa_Terminate();
+  AudioCore.Terminate();
   Result := inherited FinalizeRecord();
 end;
 
diff --git a/src/media/UAudioPlayback_Portaudio.pas b/src/media/UAudioPlayback_Portaudio.pas
index ddbd03d6..6fbae6e3 100644
--- a/src/media/UAudioPlayback_Portaudio.pas
+++ b/src/media/UAudioPlayback_Portaudio.pas
@@ -307,22 +307,16 @@ var
   paApiIndex      : TPaHostApiIndex;
   paApiInfo       : PPaHostApiInfo;
   paOutDevice     : TPaDeviceIndex;
-  err: TPaError;
 begin
   Result := false;
-
   AudioCore := TAudioCore_Portaudio.GetInstance();
 
   // initialize portaudio
-  err := Pa_Initialize();
-  if(err <> paNoError) then
-  begin
-    Log.LogError(Pa_GetErrorText(err), 'TAudioInput_Portaudio.InitializeRecord');
+  if (not AudioCore.Initialize()) then
     Exit;
-  end;
 
   paApiIndex := AudioCore.GetPreferredApiIndex();
-  if(paApiIndex = -1) then
+  if (paApiIndex = -1) then
   begin
     Log.LogError('No working Audio-API found', 'TAudioPlayback_Portaudio.InitializeAudioPlaybackEngine');
     Exit;
@@ -364,13 +358,19 @@ end;
 procedure TAudioPlayback_Portaudio.StopAudioPlaybackEngine();
 begin
   if (paStream <> nil) then
-    Pa_StopStream(paStream);
+  begin
+    Pa_CloseStream(paStream);
+    // wait until stream is closed, otherwise Terminate() might cause a segfault
+    while (Pa_IsStreamActive(paStream) = 1) do
+      ;
+    paStream := nil;
+  end;
 end;
 
 function TAudioPlayback_Portaudio.FinalizeAudioPlaybackEngine(): boolean;
 begin
-  Pa_Terminate();
-  Result := true;
+  StopAudioPlaybackEngine();
+  Result := AudioCore.Terminate();
 end;
 
 function TAudioPlayback_Portaudio.GetLatency(): double;
-- 
cgit v1.2.3