diff --git a/_examples/enumeration/enumeration.go b/_examples/enumeration/enumeration.go index 7e8f33d..0df9ce9 100644 --- a/_examples/enumeration/enumeration.go +++ b/_examples/enumeration/enumeration.go @@ -31,9 +31,11 @@ func main() { full, err := context.DeviceInfo(malgo.Playback, info.ID, malgo.Shared) if err != nil { e = err.Error() + } else if full.IsDefault { + e += ", default" } fmt.Printf(" %d: %v, %s, [%s], formats: %+v\n", - i, info.ID, info.Name(), e, full.Formats) + i, info.ID.String(), info.Name, e, full.Formats) } fmt.Println() @@ -51,8 +53,10 @@ func main() { full, err := context.DeviceInfo(malgo.Capture, info.ID, malgo.Shared) if err != nil { e = err.Error() + } else if full.IsDefault { + e += ", default" } fmt.Printf(" %d: %v, %s, [%s], formats: %+v\n", - i, info.ID, info.Name(), e, full.Formats) + i, info.ID.String(), info.Name, e, full.Formats) } } diff --git a/device_info.go b/device_info.go index e42940d..8b019a7 100644 --- a/device_info.go +++ b/device_info.go @@ -11,9 +11,19 @@ import ( // DeviceID type. type DeviceID [C.sizeof_ma_device_id]byte +func NewDeviceIDFromString(id string) (DeviceID, error) { + var deviceID DeviceID + decoded, err := hex.DecodeString(id) + if err != nil { + return deviceID, err + } + copy(deviceID[:], decoded) + return deviceID, nil +} + // String returns the string representation of the identifier. // It is the hexadecimal form of the underlying bytes of a minimum length of 2 digits, with trailing zeroes removed. -func (d DeviceID) String() string { +func (d *DeviceID) String() string { displayLen := len(d) for (displayLen > 1) && (d[displayLen-1] == 0) { displayLen-- @@ -32,42 +42,31 @@ func (d *DeviceID) cptr() *C.ma_device_id { // DeviceInfo type. type DeviceInfo struct { ID DeviceID - name [256]byte - IsDefault uint32 - FormatCount uint32 + Name string + IsDefault bool + FormatCount int Formats []DataFormat } -// Name returns the name of the device. -func (d *DeviceInfo) Name() string { - // find the first null byte in d.name - var end int - for end = 0; end < len(d.name) && d.name[end] != 0; end++ { - } - return string(d.name[:end]) -} - // String returns string. func (d *DeviceInfo) String() string { - return fmt.Sprintf("{ID: [%v], Name: %s}", d.ID, d.Name()) + return fmt.Sprintf("{ID: [%v], Name: %s}", d.ID, d.Name) } func deviceInfoFromPointer(ptr unsafe.Pointer) DeviceInfo { device := (*C.ma_device_info)(ptr) var newDevice DeviceInfo newDevice.ID = DeviceID(device.id) - for i := 0; i < len(device.name); i++ { - newDevice.name[i] = (byte)(device.name[i]) - } - newDevice.IsDefault = uint32(device.isDefault) - newDevice.FormatCount = uint32(device.nativeDataFormatCount) + newDevice.Name = C.GoString(&device.name[0]) + newDevice.IsDefault = device.isDefault == 1 // ma_true == 1 + newDevice.FormatCount = int(device.nativeDataFormatCount) newDevice.Formats = make([]DataFormat, newDevice.FormatCount) for i := 0; i < int(newDevice.FormatCount); i++ { newDevice.Formats[i] = DataFormat{ Format: FormatType(device.nativeDataFormats[i].format), - Channels: uint32(device.nativeDataFormats[i].channels), - SampleRate: uint32(device.nativeDataFormats[i].sampleRate), - Flags: uint32(device.nativeDataFormats[i].flags), + Channels: int(device.nativeDataFormats[i].channels), + SampleRate: int(device.nativeDataFormats[i].sampleRate), + Flags: DataFormatFlag(device.nativeDataFormats[i].flags), } } return newDevice @@ -75,7 +74,7 @@ func deviceInfoFromPointer(ptr unsafe.Pointer) DeviceInfo { type DataFormat struct { Format FormatType - Channels uint32 - SampleRate uint32 - Flags uint32 + Channels int + SampleRate int + Flags DataFormatFlag } diff --git a/device_info_test.go b/device_info_test.go new file mode 100644 index 0000000..463b144 --- /dev/null +++ b/device_info_test.go @@ -0,0 +1,33 @@ +package malgo_test + +import ( + "github.com/gen2brain/malgo" + "testing" +) + +func TestDeviceIDString(t *testing.T) { + // Sample data should be a device ID with the hex value 0102030405 and the string representation should be "0102030405" + sampleData := malgo.DeviceID{0x01, 0x02, 0x03, 0x04, 0x05} // remaining bytes are zero + if len(sampleData) != 256 { + t.Errorf("Expected length of 256, got %d", len(sampleData)) + } + + t.Run("can output string representation of bytes", func(t *testing.T) { + expected := "0102030405" + actual := sampleData.String() + if actual != expected { + t.Errorf("Expected %s, got %s", expected, actual) + } + }) + + t.Run("can parse string into DeviceID", func(t *testing.T) { + expected := sampleData + actual, err := malgo.NewDeviceIDFromString("0102030405") + if err != nil { + t.Errorf("Expected no error, got %v", err) + } + if actual != expected { + t.Errorf("Expected %v, got %v", expected, actual) + } + }) +} diff --git a/enumerations.go b/enumerations.go index 715a369..c0eb0db 100644 --- a/enumerations.go +++ b/enumerations.go @@ -117,6 +117,39 @@ const ( IOSSessionCategoryOptionAllowAirPlay = 0x40 // AVAudioSessionCategoryOptionAllowAirPlay ) +// DataFormatFlag type. +type DataFormatFlag uint32 + +const ( + DataFormatFlagNone DataFormatFlag = 0 + DataFormatFlagExclusiveMode DataFormatFlag = 1 << 1 +) + +var flagNames = map[DataFormatFlag]string{ + DataFormatFlagExclusiveMode: "ExclusiveMode", +} + +func (f *DataFormatFlag) Set(flag DataFormatFlag) { + *f |= flag +} + +func (f *DataFormatFlag) Clear(flag DataFormatFlag) { + *f &^= flag +} + +func (f DataFormatFlag) Has(flag DataFormatFlag) bool { + return f&flag != 0 +} + +func (f DataFormatFlag) List() []string { + var active []string + for flag, name := range flagNames { + if f.Has(flag) { + active = append(active, name) + } + } + return active +} // AAudioUsage type. type AAudioUsage uint32 diff --git a/enumerations_test.go b/enumerations_test.go new file mode 100644 index 0000000..c2f3924 --- /dev/null +++ b/enumerations_test.go @@ -0,0 +1,45 @@ +package malgo_test + +import ( + "github.com/gen2brain/malgo" + "testing" +) + +func TestDataFormatFlag(t *testing.T) { + t.Run("Set", func(t *testing.T) { + var flag malgo.DataFormatFlag + flag.Set(malgo.DataFormatFlagExclusiveMode) + if !flag.Has(malgo.DataFormatFlagExclusiveMode) { + t.Errorf("Expected flag to have DataFormatFlagExclusiveMode set") + } + }) + + t.Run("Clear", func(t *testing.T) { + var flag malgo.DataFormatFlag + flag.Set(malgo.DataFormatFlagExclusiveMode) + flag.Clear(malgo.DataFormatFlagExclusiveMode) + if flag.Has(malgo.DataFormatFlagExclusiveMode) { + t.Errorf("Expected flag to have DataFormatFlagExclusiveMode cleared") + } + }) + + t.Run("Has", func(t *testing.T) { + var flag malgo.DataFormatFlag + if flag.Has(malgo.DataFormatFlagExclusiveMode) { + t.Errorf("Expected flag to not have DataFormatFlagExclusiveMode set") + } + flag.Set(malgo.DataFormatFlagExclusiveMode) + if !flag.Has(malgo.DataFormatFlagExclusiveMode) { + t.Errorf("Expected flag to have DataFormatFlagExclusiveMode set") + } + }) + + t.Run("List", func(t *testing.T) { + var flag malgo.DataFormatFlag + flag.Set(malgo.DataFormatFlagExclusiveMode) + list := flag.List() + if len(list) != 1 || list[0] != "ExclusiveMode" { + t.Errorf("Expected list to contain 'ExclusiveMode'") + } + }) +}