CubebInputStream.cpp (6681B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 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 https://mozilla.org/MPL/2.0/. */ 6 7 #include "CubebInputStream.h" 8 9 #include "AudioSampleFormat.h" 10 #include "mozilla/Logging.h" 11 12 namespace mozilla { 13 14 extern mozilla::LazyLogModule gMediaTrackGraphLog; 15 16 #ifdef LOG_INTERNAL 17 # undef LOG_INTERNAL 18 #endif // LOG_INTERNAL 19 #define LOG_INTERNAL(level, msg, ...) \ 20 MOZ_LOG(gMediaTrackGraphLog, LogLevel::level, (msg, ##__VA_ARGS__)) 21 22 #ifdef LOG 23 # undef LOG 24 #endif // LOG 25 #define LOG(msg, ...) LOG_INTERNAL(Debug, msg, ##__VA_ARGS__) 26 27 #ifdef LOGE 28 # undef LOGE 29 #endif // LOGE 30 #define LOGE(msg, ...) LOG_INTERNAL(Error, msg, ##__VA_ARGS__) 31 32 #define InvokeCubebWithLog(func, ...) \ 33 ({ \ 34 int _retval; \ 35 _retval = InvokeCubeb(func, ##__VA_ARGS__); \ 36 if (_retval == CUBEB_OK) { \ 37 LOG("CubebInputStream %p: %s for stream %p was successful", this, #func, \ 38 mStream.get()); \ 39 } else { \ 40 LOGE("CubebInputStream %p: %s for stream %p was failed. Error %d", this, \ 41 #func, mStream.get(), _retval); \ 42 } \ 43 _retval; \ 44 }) 45 46 static cubeb_stream_params CreateStreamInitParams(uint32_t aChannels, 47 uint32_t aRate, 48 bool aIsVoice) { 49 cubeb_stream_params params; 50 params.format = CubebUtils::ToCubebFormat<AUDIO_OUTPUT_FORMAT>::value; 51 params.rate = aRate; 52 params.channels = aChannels; 53 params.layout = CUBEB_LAYOUT_UNDEFINED; 54 params.prefs = CubebUtils::GetDefaultStreamPrefs(CUBEB_DEVICE_TYPE_INPUT); 55 params.input_params = CUBEB_INPUT_PROCESSING_PARAM_NONE; 56 57 if (aIsVoice) { 58 params.prefs |= static_cast<cubeb_stream_prefs>(CUBEB_STREAM_PREF_VOICE); 59 } 60 61 return params; 62 } 63 64 void CubebInputStream::CubebDestroyPolicy::operator()( 65 cubeb_stream* aStream) const { 66 int r = cubeb_stream_register_device_changed_callback(aStream, nullptr); 67 if (r == CUBEB_OK) { 68 LOG("Unregister device changed callback for %p successfully", aStream); 69 } else { 70 LOGE("Fail to unregister device changed callback for %p. Error %d", aStream, 71 r); 72 } 73 cubeb_stream_destroy(aStream); 74 } 75 76 /* static */ 77 UniquePtr<CubebInputStream> CubebInputStream::Create(cubeb_devid aDeviceId, 78 uint32_t aChannels, 79 uint32_t aRate, 80 bool aIsVoice, 81 Listener* aListener) { 82 if (!aListener) { 83 LOGE("No available listener"); 84 return nullptr; 85 } 86 87 RefPtr<CubebUtils::CubebHandle> handle = CubebUtils::GetCubeb(); 88 if (!handle) { 89 LOGE("No valid cubeb context"); 90 CubebUtils::ReportCubebStreamInitFailure(CubebUtils::GetFirstStream()); 91 return nullptr; 92 } 93 94 cubeb_stream_params params = 95 CreateStreamInitParams(aChannels, aRate, aIsVoice); 96 uint32_t latencyFrames = CubebUtils::GetCubebMTGLatencyInFrames(¶ms); 97 98 cubeb_stream* cubebStream = nullptr; 99 100 RefPtr<Listener> listener(aListener); 101 if (int r = CubebUtils::CubebStreamInit( 102 handle->Context(), &cubebStream, "input-only stream", aDeviceId, 103 ¶ms, nullptr, nullptr, latencyFrames, DataCallback_s, 104 StateCallback_s, listener.get()); 105 r != CUBEB_OK) { 106 CubebUtils::ReportCubebStreamInitFailure(CubebUtils::GetFirstStream()); 107 LOGE("Fail to create a cubeb stream. Error %d", r); 108 return nullptr; 109 } 110 111 UniquePtr<cubeb_stream, CubebDestroyPolicy> inputStream(cubebStream); 112 113 LOG("Create a cubeb stream %p successfully", inputStream.get()); 114 115 UniquePtr<CubebInputStream> stream(new CubebInputStream( 116 listener.forget(), handle.forget(), std::move(inputStream))); 117 stream->Init(); 118 return stream; 119 } 120 121 CubebInputStream::CubebInputStream( 122 already_AddRefed<Listener>&& aListener, 123 already_AddRefed<CubebUtils::CubebHandle>&& aCubeb, 124 UniquePtr<cubeb_stream, CubebDestroyPolicy>&& aStream) 125 : mListener(aListener), mCubeb(aCubeb), mStream(std::move(aStream)) { 126 MOZ_ASSERT(mListener); 127 MOZ_ASSERT(mStream); 128 } 129 130 void CubebInputStream::Init() { 131 // cubeb_stream_register_device_changed_callback is only supported on macOS 132 // platform and MockCubeb for now. 133 InvokeCubebWithLog(cubeb_stream_register_device_changed_callback, 134 CubebInputStream::DeviceChangedCallback_s); 135 } 136 137 int CubebInputStream::Start() { return InvokeCubebWithLog(cubeb_stream_start); } 138 139 int CubebInputStream::Stop() { return InvokeCubebWithLog(cubeb_stream_stop); } 140 141 int CubebInputStream::SetProcessingParams( 142 cubeb_input_processing_params aParams) { 143 return InvokeCubebWithLog(cubeb_stream_set_input_processing_params, aParams); 144 } 145 146 int CubebInputStream::Latency(uint32_t* aLatencyFrames) { 147 return InvokeCubebWithLog(cubeb_stream_get_input_latency, aLatencyFrames); 148 } 149 150 template <typename Function, typename... Args> 151 int CubebInputStream::InvokeCubeb(Function aFunction, Args&&... aArgs) { 152 MOZ_ASSERT(mStream); 153 return aFunction(mStream.get(), std::forward<Args>(aArgs)...); 154 } 155 156 /* static */ 157 long CubebInputStream::DataCallback_s(cubeb_stream* aStream, void* aUser, 158 const void* aInputBuffer, 159 void* aOutputBuffer, long aFrames) { 160 MOZ_ASSERT(aUser); 161 MOZ_ASSERT(aInputBuffer); 162 MOZ_ASSERT(!aOutputBuffer); 163 return static_cast<Listener*>(aUser)->DataCallback(aInputBuffer, aFrames); 164 } 165 166 /* static */ 167 void CubebInputStream::StateCallback_s(cubeb_stream* aStream, void* aUser, 168 cubeb_state aState) { 169 MOZ_ASSERT(aUser); 170 static_cast<Listener*>(aUser)->StateCallback(aState); 171 } 172 173 /* static */ 174 void CubebInputStream::DeviceChangedCallback_s(void* aUser) { 175 MOZ_ASSERT(aUser); 176 static_cast<Listener*>(aUser)->DeviceChangedCallback(); 177 } 178 179 #undef LOG_INTERNAL 180 #undef LOG 181 #undef LOGE 182 183 } // namespace mozilla