From ec49bde7e1919e5a460c05903b6ccafc00be0455 Mon Sep 17 00:00:00 2001 From: tobigun Date: Mon, 19 Apr 2010 21:40:23 +0000 Subject: bugfix for crash with portaudio (all platforms): - UAudioInput_Portaudio: UnifyDeviceNames was called with the wrong index further changes: - BASS input source-names seem to be encoded with local encoding and are converted to UTF8 - Portaudio source and device names encoding is auto-detected and converted to UTF8 - some clean-up git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2252 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/URecord.pas | 16 ++++++----- src/media/UAudioInput_Bass.pas | 8 ++++-- src/media/UAudioInput_Portaudio.pas | 57 ++++++++++++++++++++++++------------- 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/base/URecord.pas b/src/base/URecord.pas index c4612adb..09ac92de 100644 --- a/src/base/URecord.pas +++ b/src/base/URecord.pas @@ -95,7 +95,7 @@ const type TAudioInputSource = record - Name: string; + Name: UTF8String; end; // soundcard input-devices information @@ -745,7 +745,7 @@ function TAudioInputBase.UnifyDeviceName(const name: UTF8String; deviceIndex: in var count: integer; // count of devices with this name - function IsDuplicate(const name: string): boolean; + function IsDuplicate(const name: UTF8String): boolean; var i: integer; begin @@ -754,11 +754,13 @@ var for i := 0 to deviceIndex-1 do begin if (AudioInputProcessor.DeviceList[i] <> nil) then - if (AudioInputProcessor.DeviceList[i].Name = name) then - begin - Result := true; - Break; - end; + begin + if (AudioInputProcessor.DeviceList[i].Name = name) then + begin + Result := true; + Break; + end; + end; end; end; diff --git a/src/media/UAudioInput_Bass.pas b/src/media/UAudioInput_Bass.pas index e51ba254..b8f914c5 100644 --- a/src/media/UAudioInput_Bass.pas +++ b/src/media/UAudioInput_Bass.pas @@ -392,8 +392,8 @@ begin BassDevice.BassDeviceID := BassDeviceID; - // bass device name seems to be encoded w/ local encoding - // to-do : check if this is correct + // BASS device names seem to be encoded with local encoding + // TODO: works for windows, check Linux + Mac OS X Descr := DecodeStringUTF8(DeviceInfo.name, encLocale); BassDevice.Name := UnifyDeviceName(Descr, DeviceIndex); @@ -463,7 +463,9 @@ begin break; SetLength(BassDevice.Source, Length(BassDevice.Source)+1); - BassDevice.Source[SourceIndex].Name := SourceName; + // BASS source names seem to be encoded with local encoding + // TODO: works for windows, check Linux + Mac OS X + BassDevice.Source[SourceIndex].Name := DecodeStringUTF8(SourceName, encLocale); // get input-source info Flags := BASS_RecordGetInput(SourceIndex, PSingle(nil)^); diff --git a/src/media/UAudioInput_Portaudio.pas b/src/media/UAudioInput_Portaudio.pas index 95b0f104..26919d42 100644 --- a/src/media/UAudioInput_Portaudio.pas +++ b/src/media/UAudioInput_Portaudio.pas @@ -46,6 +46,8 @@ uses {$ENDIF} portaudio, UAudioCore_Portaudio, + UUnicodeUtils, + UTextEncoding, UIni, ULog, UMain, @@ -88,6 +90,20 @@ function MicrophoneTestCallback(input: pointer; output: pointer; frameCount: lon inputDevice: pointer): integer; cdecl; forward; +{** + * Converts a string returned by Portaudio into UTF8. + * If the string already is in UTF8 no conversion is performed, otherwise + * the local encoding is used. + *} +function ConvertPaStringToUTF8(const Str: RawByteString): UTF8String; +begin + if (IsUTF8String(Str)) then + Result := Str + else + Result := DecodeStringUTF8(Str, encLocale); +end; + + { TPortaudioInputDevice } function TPortaudioInputDevice.Open(): boolean; @@ -95,6 +111,9 @@ var Error: TPaError; inputParams: TPaStreamParameters; deviceInfo: PPaDeviceInfo; + {$IFDEF UsePortmixer} + SourceIndex: integer; + {$ENDIF} begin Result := false; @@ -269,13 +288,13 @@ end; function TAudioInput_Portaudio.EnumDevices(): boolean; var i: integer; + deviceName: UTF8String; paApiIndex: TPaHostApiIndex; paApiInfo: PPaHostApiInfo; - deviceName: UTF8String; - deviceIndex: TPaDeviceIndex; - deviceInfo: PPaDeviceInfo; + paDeviceIndex:TPaDeviceIndex; + paDeviceInfo: PPaDeviceInfo; channelCnt: integer; - soundcardCnt: integer; + deviceIndex: integer; err: TPaError; errMsg: string; paDevice: TPortaudioInputDevice; @@ -288,7 +307,7 @@ var mixer: PPxMixer; sourceCnt: integer; sourceIndex: integer; - sourceName: string; + sourceName: UTF8String; {$ENDIF} begin Result := false; @@ -303,17 +322,17 @@ begin paApiInfo := Pa_GetHostApiInfo(paApiIndex); - soundcardCnt := 0; + deviceIndex := 0; // init array-size to max. input-devices count SetLength(AudioInputProcessor.DeviceList, paApiInfo^.deviceCount); for i:= 0 to High(AudioInputProcessor.DeviceList) do begin // convert API-specific device-index to global index - deviceIndex := Pa_HostApiDeviceIndexToDeviceIndex(paApiIndex, i); - deviceInfo := Pa_GetDeviceInfo(deviceIndex); + paDeviceIndex := Pa_HostApiDeviceIndexToDeviceIndex(paApiIndex, i); + paDeviceInfo := Pa_GetDeviceInfo(paDeviceIndex); - channelCnt := deviceInfo^.maxInputChannels; + channelCnt := paDeviceInfo^.maxInputChannels; // current device is no input device -> skip if (channelCnt <= 0) then @@ -326,25 +345,25 @@ begin channelCnt := 2; paDevice := TPortaudioInputDevice.Create(); - AudioInputProcessor.DeviceList[soundCardCnt] := paDevice; + AudioInputProcessor.DeviceList[deviceIndex] := paDevice; // retrieve device-name - deviceName := deviceInfo^.name; + deviceName := ConvertPaStringToUTF8(paDeviceInfo^.name); paDevice.Name := UnifyDeviceName(deviceName, deviceIndex); - paDevice.PaDeviceIndex := deviceIndex; + paDevice.PaDeviceIndex := paDeviceIndex; - sampleRate := deviceInfo^.defaultSampleRate; + sampleRate := paDeviceInfo^.defaultSampleRate; // on vista and xp the defaultLowInputLatency may be set to 0 but it works. // TODO: correct too low latencies (what is a too low latency, maybe < 10ms?) - latency := deviceInfo^.defaultLowInputLatency; + latency := paDeviceInfo^.defaultLowInputLatency; // setup desired input parameters // TODO: retry with input-latency set to 20ms (defaultLowInputLatency might // not be set correctly in OSS) with inputParams do begin - device := deviceIndex; + device := paDeviceIndex; channelCount := channelCnt; sampleFormat := paInt16; suggestedLatency := latency; @@ -421,7 +440,7 @@ begin for sourceIndex := 1 to sourceCnt do begin sourceName := Px_GetInputSourceName(mixer, sourceIndex-1); - paDevice.Source[sourceIndex].Name := sourceName; + paDevice.Source[sourceIndex].Name := ConvertPaStringToUTF8(sourceName); end; Px_CloseMixer(mixer); @@ -430,13 +449,13 @@ begin // close test-stream Pa_CloseStream(stream); - Inc(soundCardCnt); + Inc(deviceIndex); end; // adjust size to actual input-device count - SetLength(AudioInputProcessor.DeviceList, soundCardCnt); + SetLength(AudioInputProcessor.DeviceList, deviceIndex); - Log.LogStatus('#Input-Devices: ' + inttostr(soundCardCnt), 'Portaudio'); + Log.LogStatus('#Input-Devices: ' + inttostr(deviceIndex), 'Portaudio'); Result := true; end; -- cgit v1.2.3