1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "WebAudioUtils.h"
8 #include "AudioNodeTrack.h"
9 #include "blink/HRTFDatabaseLoader.h"
10 
11 #include "nsComponentManagerUtils.h"
12 #include "nsContentUtils.h"
13 #include "nsIConsoleService.h"
14 #include "nsIScriptError.h"
15 #include "nsJSUtils.h"
16 #include "nsServiceManagerUtils.h"
17 #include "AudioEventTimeline.h"
18 
19 #include "mozilla/SchedulerGroup.h"
20 
21 namespace mozilla {
22 
23 LazyLogModule gWebAudioAPILog("WebAudioAPI");
24 
25 namespace dom {
26 
ConvertAudioTimelineEventToTicks(AudioTimelineEvent & aEvent,AudioNodeTrack * aDest)27 void WebAudioUtils::ConvertAudioTimelineEventToTicks(AudioTimelineEvent& aEvent,
28                                                      AudioNodeTrack* aDest) {
29   aEvent.SetTimeInTicks(
30       aDest->SecondsToNearestTrackTime(aEvent.Time<double>()));
31   aEvent.mTimeConstant *= aDest->mSampleRate;
32   aEvent.mDuration *= aDest->mSampleRate;
33 }
34 
Shutdown()35 void WebAudioUtils::Shutdown() { WebCore::HRTFDatabaseLoader::shutdown(); }
36 
SpeexResamplerProcess(SpeexResamplerState * aResampler,uint32_t aChannel,const float * aIn,uint32_t * aInLen,float * aOut,uint32_t * aOutLen)37 int WebAudioUtils::SpeexResamplerProcess(SpeexResamplerState* aResampler,
38                                          uint32_t aChannel, const float* aIn,
39                                          uint32_t* aInLen, float* aOut,
40                                          uint32_t* aOutLen) {
41 #ifdef MOZ_SAMPLE_TYPE_S16
42   AutoTArray<AudioDataValue, WEBAUDIO_BLOCK_SIZE * 4> tmp1;
43   AutoTArray<AudioDataValue, WEBAUDIO_BLOCK_SIZE * 4> tmp2;
44   tmp1.SetLength(*aInLen);
45   tmp2.SetLength(*aOutLen);
46   ConvertAudioSamples(aIn, tmp1.Elements(), *aInLen);
47   int result = speex_resampler_process_int(
48       aResampler, aChannel, tmp1.Elements(), aInLen, tmp2.Elements(), aOutLen);
49   ConvertAudioSamples(tmp2.Elements(), aOut, *aOutLen);
50   return result;
51 #else
52   return speex_resampler_process_float(aResampler, aChannel, aIn, aInLen, aOut,
53                                        aOutLen);
54 #endif
55 }
56 
SpeexResamplerProcess(SpeexResamplerState * aResampler,uint32_t aChannel,const int16_t * aIn,uint32_t * aInLen,float * aOut,uint32_t * aOutLen)57 int WebAudioUtils::SpeexResamplerProcess(SpeexResamplerState* aResampler,
58                                          uint32_t aChannel, const int16_t* aIn,
59                                          uint32_t* aInLen, float* aOut,
60                                          uint32_t* aOutLen) {
61   AutoTArray<AudioDataValue, WEBAUDIO_BLOCK_SIZE * 4> tmp;
62 #ifdef MOZ_SAMPLE_TYPE_S16
63   tmp.SetLength(*aOutLen);
64   int result = speex_resampler_process_int(aResampler, aChannel, aIn, aInLen,
65                                            tmp.Elements(), aOutLen);
66   ConvertAudioSamples(tmp.Elements(), aOut, *aOutLen);
67   return result;
68 #else
69   tmp.SetLength(*aInLen);
70   ConvertAudioSamples(aIn, tmp.Elements(), *aInLen);
71   int result = speex_resampler_process_float(
72       aResampler, aChannel, tmp.Elements(), aInLen, aOut, aOutLen);
73   return result;
74 #endif
75 }
76 
SpeexResamplerProcess(SpeexResamplerState * aResampler,uint32_t aChannel,const int16_t * aIn,uint32_t * aInLen,int16_t * aOut,uint32_t * aOutLen)77 int WebAudioUtils::SpeexResamplerProcess(SpeexResamplerState* aResampler,
78                                          uint32_t aChannel, const int16_t* aIn,
79                                          uint32_t* aInLen, int16_t* aOut,
80                                          uint32_t* aOutLen) {
81 #ifdef MOZ_SAMPLE_TYPE_S16
82   return speex_resampler_process_int(aResampler, aChannel, aIn, aInLen, aOut,
83                                      aOutLen);
84 #else
85   AutoTArray<AudioDataValue, WEBAUDIO_BLOCK_SIZE * 4> tmp1;
86   AutoTArray<AudioDataValue, WEBAUDIO_BLOCK_SIZE * 4> tmp2;
87   tmp1.SetLength(*aInLen);
88   tmp2.SetLength(*aOutLen);
89   ConvertAudioSamples(aIn, tmp1.Elements(), *aInLen);
90   int result = speex_resampler_process_float(
91       aResampler, aChannel, tmp1.Elements(), aInLen, tmp2.Elements(), aOutLen);
92   ConvertAudioSamples(tmp2.Elements(), aOut, *aOutLen);
93   return result;
94 #endif
95 }
96 
LogToDeveloperConsole(uint64_t aWindowID,const char * aKey)97 void WebAudioUtils::LogToDeveloperConsole(uint64_t aWindowID,
98                                           const char* aKey) {
99   // This implementation is derived from dom/media/VideoUtils.cpp, but we
100   // use a windowID so that the message is delivered to the developer console.
101   // It is similar to ContentUtils::ReportToConsole, but also works off main
102   // thread.
103   if (!NS_IsMainThread()) {
104     nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
105         "dom::WebAudioUtils::LogToDeveloperConsole",
106         [aWindowID, aKey] { LogToDeveloperConsole(aWindowID, aKey); });
107     SchedulerGroup::Dispatch(TaskCategory::Other, task.forget());
108     return;
109   }
110 
111   nsCOMPtr<nsIConsoleService> console(
112       do_GetService("@mozilla.org/consoleservice;1"));
113   if (!console) {
114     NS_WARNING("Failed to log message to console.");
115     return;
116   }
117 
118   nsAutoString spec;
119   uint32_t aLineNumber = 0, aColumnNumber = 0;
120   JSContext* cx = nsContentUtils::GetCurrentJSContext();
121   if (cx) {
122     nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber, &aColumnNumber);
123   }
124 
125   nsresult rv;
126   nsCOMPtr<nsIScriptError> errorObject =
127       do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
128   if (!errorObject) {
129     NS_WARNING("Failed to log message to console.");
130     return;
131   }
132 
133   nsAutoString result;
134   rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES, aKey,
135                                           result);
136 
137   if (NS_FAILED(rv)) {
138     NS_WARNING("Failed to log message to console.");
139     return;
140   }
141 
142   errorObject->InitWithWindowID(result, spec, u""_ns, aLineNumber,
143                                 aColumnNumber, nsIScriptError::warningFlag,
144                                 "Web Audio", aWindowID);
145   console->LogMessage(errorObject);
146 }
147 
148 }  // namespace dom
149 }  // namespace mozilla
150