diff --git a/Libraries/LibWeb/WebAudio/AudioContext.cpp b/Libraries/LibWeb/WebAudio/AudioContext.cpp index 530321bda7e..345fc102e83 100644 --- a/Libraries/LibWeb/WebAudio/AudioContext.cpp +++ b/Libraries/LibWeb/WebAudio/AudioContext.cpp @@ -59,19 +59,26 @@ WebIDL::ExceptionOr> AudioContext::construct_impl(JS::Real // 1. If sinkId is specified, let sinkId be the value of contextOptions.sinkId and run the following substeps: // 2. Set the internal latency of context according to contextOptions.latencyHint, as described in latencyHint. - switch (context_options->latency_hint) { - case Bindings::AudioContextLatencyCategory::Balanced: - // FIXME: Determine optimal settings for balanced. - break; - case Bindings::AudioContextLatencyCategory::Interactive: - // FIXME: Determine optimal settings for interactive. - break; - case Bindings::AudioContextLatencyCategory::Playback: - // FIXME: Determine optimal settings for playback. - break; - default: - VERIFY_NOT_REACHED(); - } + context_options->latency_hint.visit( + [&](Bindings::AudioContextLatencyCategory category) { + switch (category) { + case Bindings::AudioContextLatencyCategory::Balanced: + // FIXME: Determine optimal settings for balanced. + break; + case Bindings::AudioContextLatencyCategory::Interactive: + // FIXME: Determine optimal settings for interactive. + break; + case Bindings::AudioContextLatencyCategory::Playback: + // FIXME: Determine optimal settings for playback. + break; + default: + VERIFY_NOT_REACHED(); + } + }, + [&](double latency_seconds) { + // FIXME: Determine optimal settings for numeric latency hint. + (void)latency_seconds; + }); // 3: If contextOptions.sampleRate is specified, set the sampleRate of context to this value. if (context_options->sample_rate.has_value()) { diff --git a/Libraries/LibWeb/WebAudio/AudioContext.h b/Libraries/LibWeb/WebAudio/AudioContext.h index 8f606b634aa..66fd9c69c6f 100644 --- a/Libraries/LibWeb/WebAudio/AudioContext.h +++ b/Libraries/LibWeb/WebAudio/AudioContext.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -14,7 +15,7 @@ namespace Web::WebAudio { struct AudioContextOptions { - Bindings::AudioContextLatencyCategory latency_hint = Bindings::AudioContextLatencyCategory::Interactive; + Variant latency_hint = Bindings::AudioContextLatencyCategory::Interactive; Optional sample_rate; }; diff --git a/Libraries/LibWeb/WebAudio/AudioContext.idl b/Libraries/LibWeb/WebAudio/AudioContext.idl index 36858285ccb..010c1880372 100644 --- a/Libraries/LibWeb/WebAudio/AudioContext.idl +++ b/Libraries/LibWeb/WebAudio/AudioContext.idl @@ -20,7 +20,7 @@ interface AudioContext : BaseAudioContext { }; dictionary AudioContextOptions { - AudioContextLatencyCategory latencyHint = "interactive"; + (AudioContextLatencyCategory or double) latencyHint = "interactive"; float sampleRate; }; diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index 83be3f69827..44d85f8ff85 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -1607,8 +1607,8 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter )~~~"); // NOTE: generate_to_cpp doesn't use the parameter name. // NOTE: generate_to_cpp will use to_{u32,etc.} which uses to_number internally and will thus use TRY, but it cannot throw as we know we are dealing with a number. - IDL::Parameter parameter { .type = *numeric_type, .name = ByteString::empty(), .optional_default_value = {}, .extended_attributes = {} }; - generate_to_cpp(union_generator, parameter, js_name, js_suffix, ByteString::formatted("{}{}_number", js_name, js_suffix), interface, false, false, {}, false, recursion_depth + 1); + IDL::Parameter idl_parameter { .type = *numeric_type, .name = parameter.name, .optional_default_value = {}, .extended_attributes = {} }; + generate_to_cpp(union_generator, idl_parameter, js_name, js_suffix, ByteString::formatted("{}{}_number", js_name, js_suffix), interface, false, false, {}, false, recursion_depth + 1); union_generator.append(R"~~~( return { @js_name@@js_suffix@_number }; @@ -1633,6 +1633,47 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter )~~~"); } + bool includes_enumeration = false; + for (auto& type : types) { + if (interface.enumerations.contains(type->name())) { + includes_enumeration = true; + break; + } + } + + // If V is a string and types includes an enumeration type, attempt to convert the string to that enumeration. + // Example: Libraries/LibWeb/WebAudio/AudioContext.idl (AudioContextOptions.latencyHint: (AudioContextLatencyCategory or double)). + if (includes_enumeration) { + union_generator.append(R"~~~( + if (@js_name@@js_suffix@.is_string()) { + auto @js_name@@js_suffix@_enum_string = TRY(@js_name@@js_suffix@.to_string(vm)); +)~~~"); + + for (auto& type : types) { + if (!interface.enumerations.contains(type->name())) + continue; + + auto& enumeration = interface.enumerations.find(type->name())->value; + auto enum_type = IDL::idl_type_name_to_cpp_type(*type, interface); + + auto enum_generator = union_generator.fork(); + enum_generator.set("enum.type", enum_type.name); + + for (auto& it : enumeration.translated_cpp_names) { + enum_generator.set("enum.alt.name", it.key); + enum_generator.set("enum.alt.value", it.value); + enum_generator.append(R"~~~( + if (@js_name@@js_suffix@_enum_string == "@enum.alt.name@"sv) + return @union_type@ { @enum.type@::@enum.alt.value@ }; +)~~~"); + } + } + + union_generator.append(R"~~~( + } +)~~~"); + } + RefPtr string_type; for (auto& type : types) { if (type->is_string()) { @@ -1645,8 +1686,8 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter // 14. If types includes a string type, then return the result of converting V to that type. // NOTE: Currently all string types are converted to String. - IDL::Parameter parameter { .type = *string_type, .name = ByteString::empty(), .optional_default_value = {}, .extended_attributes = {} }; - generate_to_cpp(union_generator, parameter, js_name, js_suffix, ByteString::formatted("{}{}_string", js_name, js_suffix), interface, legacy_null_to_empty_string, false, {}, false, recursion_depth + 1); + IDL::Parameter idl_parameter { .type = *string_type, .name = parameter.name, .optional_default_value = {}, .extended_attributes = {} }; + generate_to_cpp(union_generator, idl_parameter, js_name, js_suffix, ByteString::formatted("{}{}_string", js_name, js_suffix), interface, legacy_null_to_empty_string, false, {}, false, recursion_depth + 1); union_generator.append(R"~~~( return { @js_name@@js_suffix@_string }; @@ -1674,8 +1715,8 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter // NOTE: generate_to_cpp doesn't use the parameter name. // NOTE: generate_to_cpp will use to_{u32,etc.} which uses to_number internally and will thus use TRY, but it cannot throw as we know we are dealing with a number. - IDL::Parameter parameter { .type = *numeric_type, .name = ByteString::empty(), .optional_default_value = {}, .extended_attributes = {} }; - generate_to_cpp(union_numeric_type_generator, parameter, "x", ByteString::empty(), "x_number", interface, false, false, {}, false, recursion_depth + 1); + IDL::Parameter idl_parameter { .type = *numeric_type, .name = parameter.name, .optional_default_value = {}, .extended_attributes = {} }; + generate_to_cpp(union_numeric_type_generator, idl_parameter, "x", ByteString::empty(), "x_number", interface, false, false, {}, false, recursion_depth + 1); union_numeric_type_generator.append(R"~~~( return x_number; @@ -1685,8 +1726,8 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter // NOTE: generate_to_cpp doesn't use the parameter name. // NOTE: generate_to_cpp will use to_{u32,etc.} which uses to_number internally and will thus use TRY, but it cannot throw as we know we are dealing with a number. - IDL::Parameter parameter { .type = *numeric_type, .name = ByteString::empty(), .optional_default_value = {}, .extended_attributes = {} }; - generate_to_cpp(union_generator, parameter, js_name, js_suffix, ByteString::formatted("{}{}_number", js_name, js_suffix), interface, false, false, {}, false, recursion_depth + 1); + IDL::Parameter idl_parameter { .type = *numeric_type, .name = parameter.name, .optional_default_value = {}, .extended_attributes = {} }; + generate_to_cpp(union_generator, idl_parameter, js_name, js_suffix, ByteString::formatted("{}{}_number", js_name, js_suffix), interface, false, false, {}, false, recursion_depth + 1); union_generator.append(R"~~~( return { @js_name@@js_suffix@_number }; @@ -1736,12 +1777,12 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter )~~~"); } else if (optional_default_value == "\"\"") { union_generator.append(R"~~~( - @union_type@ @cpp_name@ = @js_name@@js_suffix@.is_undefined() ? String {} : TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@)); + @union_type@ @cpp_name@ = @js_name@@js_suffix@.is_undefined() ? TRY(@js_name@@js_suffix@_to_variant(JS::Value(JS::PrimitiveString::create(vm, String {})))) : TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@)); )~~~"); } else if (optional_default_value->starts_with("\""sv) && optional_default_value->ends_with("\""sv)) { union_generator.set("default_string_value", optional_default_value.value()); union_generator.append(R"~~~( - @union_type@ @cpp_name@ = @js_name@@js_suffix@.is_undefined() ? MUST(String::from_utf8(@default_string_value@sv)) : TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@)); + @union_type@ @cpp_name@ = @js_name@@js_suffix@.is_undefined() ? TRY(@js_name@@js_suffix@_to_variant(JS::Value(JS::PrimitiveString::create(vm, MUST(String::from_utf8(@default_string_value@sv)))))) : TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@)); )~~~"); } else if (optional_default_value == "{}") { VERIFY(dictionary_type); diff --git a/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.txt b/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.txt index d8bae9472c8..b3c856e46b6 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.txt @@ -1,12 +1,11 @@ -Harness status: Error +Harness status: OK -Found 32 tests +Found 37 tests -27 Pass -5 Fail +37 Pass Pass # AUDIT TASK RUNNER STARTED. Pass Executing "test-audiocontextoptions-latencyHint-basic" -Fail Executing "test-audiocontextoptions-latencyHint-double" +Pass Executing "test-audiocontextoptions-latencyHint-double" Pass Executing "test-audiocontextoptions-sampleRate" Pass Audit report Pass > [test-audiocontextoptions-latencyHint-basic] Test creating contexts with basic latencyHint types. @@ -21,12 +20,17 @@ Pass context = new AudioContext({'latencyHint': 'playback'}) did not throw an Pass playback baseLatency is greater than or equal to 0. Pass < [test-audiocontextoptions-latencyHint-basic] All assertions passed. (total 9 assertions) Pass > [test-audiocontextoptions-latencyHint-double] Test creating contexts with explicit latencyHint values. -Fail X context = new AudioContext({'latencyHint': interactiveLatency/2}) incorrectly threw TypeError: "Invalid value '0' for enumeration type 'AudioContextLatencyCategory'". +Pass context = new AudioContext({'latencyHint': interactiveLatency/2}) did not throw an exception. Pass double-constructor baseLatency small is less than or equal to 0. -Fail X context = new AudioContext({'latencyHint': validLatency}) incorrectly threw TypeError: "Invalid value '0' for enumeration type 'AudioContextLatencyCategory'". +Pass context = new AudioContext({'latencyHint': validLatency}) did not throw an exception. Pass double-constructor baseLatency inrange 1 is greater than or equal to 0. Pass double-constructor baseLatency inrange 2 is less than or equal to 0. -Fail X creating two high latency contexts incorrectly threw TypeError: "Invalid value '0' for enumeration type 'AudioContextLatencyCategory'". +Pass creating two high latency contexts did not throw an exception. +Pass high latency context baseLatency is equal to 0. +Pass high latency context baseLatency is greater than or equal to 0. +Pass context = new AudioContext({'latencyHint': 'foo'}) threw TypeError: "Expected latencyHint to be a finite floating-point number". +Pass context = new AudioContext('latencyHint') threw TypeError: "Not an object of type AudioContextOptions". +Pass < [test-audiocontextoptions-latencyHint-double] All assertions passed. (total 10 assertions) Pass > [test-audiocontextoptions-sampleRate] Test creating contexts with non-default sampleRate values. Pass context = new AudioContext({sampleRate: 1}) threw NotSupportedError: "Sample rate is outside of allowed range". Pass context = new AudioContext({sampleRate: 1000000}) threw NotSupportedError: "Sample rate is outside of allowed range". @@ -35,4 +39,4 @@ Pass context = new AudioContext({sampleRate: 0}) threw NotSupportedError: "Sam Pass context = new AudioContext({sampleRate: 24000}) did not throw an exception. Pass sampleRate inrange is equal to 24000. Pass < [test-audiocontextoptions-sampleRate] All assertions passed. (total 6 assertions) -Fail # AUDIT TASK RUNNER FINISHED: 1 out of 3 tasks were failed. \ No newline at end of file +Pass # AUDIT TASK RUNNER FINISHED: 3 tasks ran successfully. \ No newline at end of file