
Recherche avancée
Médias (1)
-
Rennes Emotion Map 2010-11
19 octobre 2011, par
Mis à jour : Juillet 2013
Langue : français
Type : Texte
Autres articles (94)
-
Contribute to documentation
13 avril 2011Documentation is vital to the development of improved technical capabilities.
MediaSPIP welcomes documentation by users as well as developers - including : critique of existing features and functions articles contributed by developers, administrators, content producers and editors screenshots to illustrate the above translations of existing documentation into other languages
To contribute, register to the project users’ mailing (...) -
Use, discuss, criticize
13 avril 2011, parTalk to people directly involved in MediaSPIP’s development, or to people around you who could use MediaSPIP to share, enhance or develop their creative projects.
The bigger the community, the more MediaSPIP’s potential will be explored and the faster the software will evolve.
A discussion list is available for all exchanges between users. -
Sélection de projets utilisant MediaSPIP
29 avril 2011, parLes exemples cités ci-dessous sont des éléments représentatifs d’usages spécifiques de MediaSPIP pour certains projets.
Vous pensez avoir un site "remarquable" réalisé avec MediaSPIP ? Faites le nous savoir ici.
Ferme MediaSPIP @ Infini
L’Association Infini développe des activités d’accueil, de point d’accès internet, de formation, de conduite de projets innovants dans le domaine des Technologies de l’Information et de la Communication, et l’hébergement de sites. Elle joue en la matière un rôle unique (...)
Sur d’autres sites (7682)
-
Overcoming Fintech and Finserv’s Biggest Data Analytics Challenges
Data powers innovation in financial technology (fintech), from personalized banking services to advanced fraud detection systems. Industry leaders recognize the value of strong security measures and customer privacy. A recent survey highlights this focus, with 72% of finance Chief Risk Officers identifying cybersecurity as their primary concern.
Beyond cybersecurity, fintech and financial services (finserv) companies are bogged down with massive amounts of data spread throughout disconnected systems. Between this, a complex regulatory landscape and an increasingly tech-savvy and sceptical consumer base, fintech and finserv companies have a lot on their plates.
How can marketing teams get the information they need while staying focused on compliance and providing customer value ?
This article will examine strategies to address common challenges in the finserv and fintech industries. We’ll focus on using appropriate tools, following effective data management practices, and learning from traditional banks’ approaches to similar issues.
What are the biggest fintech data analytics challenges, and how do they intersect with traditional banking ?
Recent years have been tough for the fintech industry, especially after the pandemic. This period has brought new hurdles in data analysis and made existing ones more complex. As the market stabilises, both fintech and finserve companies must tackle these evolving data issues.
Let’s examine some of the most significant data analytics challenges facing the fintech industry, starting with an issue that’s prevalent across the financial sector :
1. Battling data silos
In a recent survey by InterSystems, 54% of financial institution leaders said data silos are their biggest barrier to innovation, while 62% said removing silos is their priority data strategy for the next year.
Data silos segregate data repositories across departments, products and other divisions. This is a major issue in traditional banking and something fintech companies should avoid inheriting at all costs.
Siloed data makes it harder for decision-makers to view business performance with 360-degree clarity. It’s also expensive to maintain and operationalise and can evolve into privacy and data compliance issues if left unchecked.
To avoid or remove data silos, develop a data governance framework and centralise your data repositories. Next, simplify your analytics stack into as few integrated tools as possible because complex tech stacks are one of the leading causes of data silos.
Use an analytics system like Matomo that incorporates web analytics, marketing attribution and CRO testing into one toolkit.
Matomo’s support plans help you implement a data system to meet the unique needs of your business and avoid issues like data silos. We also offer data warehouse exporting as a feature to bring all of your web analytics, customer data, support data, etc., into one centralised location.
Try Matomo for free today, or contact our sales team to discuss support plans.
2. Compliance with laws and regulations
A survey by Alloy reveals that 93% of fintech companies find it difficult to meet compliance regulations. The cost of staying compliant tops their list of worries (23%), outranking even the financial hit from fraud (21%) – and this in a year marked by cyber threats.
Data privacy laws are constantly changing, and the landscape varies across global regions, making adherence even more challenging for fintechs and traditional banks operating in multiple markets.
In the US market, companies grapple with regulations at both federal and state levels. Here are some of the state-level legislation coming into effect for 2024-2026 :
- Oregon – Oregon Consumer Privacy Act (July 1, 2024)
- Florida – Florida Digital Bill of Rights (July 1, 2024)
- Texas – Texas Data Privacy and Security Act (July 1, 2024)
- Montana – Montana Consumer Data Privacy Act (October 1, 2024)
- Delaware – Delaware Personal Privacy Act (January 1, 2025)
- Iowa – Iowa Consumer Data Protection Act (January 1, 2025)
- New Jersey – SB 332 (January 15, 2025)
- Tennessee – Tennessee Information Protection Act (July 1, 2025)
- Indiana – Indiana Consumer Data Protection Act ( January 1, 2026)
Other countries are also ramping up regional regulations. For instance, Canada has Quebec’s Act Respecting the Protection of Personal Information in the Private Sector and British Columbia’s Personal Information Protection Act (BC PIPA).
Ignorance of country- or region-specific laws will not stop companies from suffering the consequences of violating them.
The only answer is to invest in adherence and manage business growth accordingly. Ultimately, compliance is more affordable than non-compliance – not only in terms of the potential fines but also the potential risks to reputation, consumer trust and customer loyalty.
This is an expensive lesson that fintech and traditional financial companies have had to learn together. GDPR regulators hit CaixaBank S.A, one of Spain’s largest banks, with multiple multi-million Euro fines, and Klarna Bank AB, a popular Swedish fintech company, for €720,000.
To avoid similar fates, companies should :
- Build solid data systems
- Hire compliance experts
- Train their teams thoroughly
- Choose data analytics tools carefully
Remember, even popular tools like Google Analytics aren’t automatically safe. Find out how Matomo helps you gather useful insights while sticking to rules like GDPR.
3. Protecting against data security threats
Cyber threats are increasing in volume and sophistication, with the financial sector becoming the most breached in 2023.
The cybersecurity risks will only worsen, with WEF estimating annual cybercrime expenses of up to USD $10.5 trillion globally by 2025, up from USD $3 trillion in 2015.
While technology brings new security solutions, it also amplifies existing risks and creates new ones. A 2024 McKinsey report warns that the risk of data breaches will continue to increase as the financial industry increasingly relies on third-party data tools and cloud computing services unless they simultaneously improve their security posture.
The reality is that adopting a third-party data system without taking the proper precautions means adopting its security vulnerabilities.
In 2023, the MOVEit data breach affected companies worldwide, including financial institutions using its file transfer system. One hack created a global data crisis, potentially affecting the customer data of every company using this one software product.
The McKinsey report emphasises choosing tools wisely. Why ? Because when customer data is compromised, it’s your company that takes the heat, not the tool provider. As the report states :
“Companies need reliable, insightful metrics and reporting (such as security compliance, risk metrics and vulnerability tracking) to prove to regulators the health of their security capabilities and to manage those capabilities.”
Don’t put user or customer data in the hands of companies you can’t trust. Work with providers that care about security as much as you do. With Matomo, you own all of your data, ensuring it’s never used for unknown purposes.
4. Protecting users’ privacy
With security threats increasing, fintech companies and traditional banks must prioritise user privacy protection. Users are also increasingly aware of privacy threats and ready to walk away from companies that lose their trust.
Cisco’s 2023 Data Privacy Benchmark Study reveals some eye-opening statistics :
- 94% of companies said their customers wouldn’t buy from them if their data wasn’t protected, and
- 95% see privacy as a business necessity, not just a legal requirement.
Modern financial companies must balance data collection and management with increasing privacy demands. This may sound contradictory for companies reliant on dated practices like third-party cookies, but they need to learn to thrive in a cookieless web as customers move to banks and service providers that have strong data ethics.
This privacy protection journey starts with implementing web analytics ethically from the very first session.
The most important elements of ethically-sound web analytics in fintech are :
- 100% data ownership : Make sure your data isn’t used in other ways by the tools that collect it.
- Respecting user privacy : Only collect the data you absolutely need to do your job and avoid personally identifiable information.
- Regulatory compliance : Stick with solutions built for compliance to stay out of legal trouble.
- Data transparency : Know how your tools use your data and let your customers know how you use it.
Read our guide to ethical web analytics for more information.
5. Comparing customer trust across industries
While fintech companies are making waves in the financial world, they’re still playing catch-up when it comes to earning customer trust. According to RFI Global, fintech has a consumer trust score of 5.8/10 in 2024, while traditional banking scores 7.6/10.
This trust gap isn’t just about perception – it’s rooted in real issues :
- Security breaches are making headlines more often.
- Privacy regulations like GDPR are making consumers more aware of their rights.
- Some fintech companies are struggling to handle fraud effectively.
According to the UK’s Payment Systems Regulator, digital banking brands Monzo and Starling had some of the highest fraudulent activity rates in 2022. Yet, Monzo only reimbursed 6% of customers who reported suspicious transactions, compared to 70% for NatWest and 91% for Nationwide.
So, what can fintech firms do to close this trust gap ?
- Start with privacy-centric analytics from day one. This shows customers you value their privacy from the get-go.
- Build and maintain a long-term reputation free of data leaks and privacy issues. One major breach can undo years of trust-building.
- Learn from traditional banks when it comes to handling issues like fraudulent transactions, identity theft, and data breaches. Prompt, customer-friendly resolutions go a long way.
- Remember : cutting-edge financial technology doesn’t make up for poor customer care. If your digital bank won’t refund customers who’ve fallen victim to credit card fraud, they’ll likely switch to a traditional bank that will.
The fintech sector has made strides in innovation, but there’s still work to do in establishing trustworthiness. By focusing on robust security, transparent practices, and excellent customer service, fintech companies can bridge the trust gap and compete more effectively with traditional banks.
6. Collecting quality data
Adhering to data privacy regulations, protecting user data and implementing ethical analytics raises another challenge. How can companies do all of these things and still collect reliable, quality data ?
Google’s answer is using predictive models, but this replaces real data with calculations and guesswork. The worst part is that Google Analytics doesn’t even let you use all of the data you collect in the first place. Instead, it uses something called data sampling once you pass certain thresholds.
In practice, this means that Google Analytics uses a limited set of your data to calculate reports. We’ve discussed GA4 data sampling at length before, but there are two key problems for companies here :
- A sample size that’s too small won’t give you a full representation of your data.
- The more visitors that come to your site, the less accurate your reports will become.
For high-growth companies, data sampling simply can’t keep up. Financial marketers widely recognise the shortcomings of big tech analytics providers. In fact, 80% of them say they’re concerned about data bias from major providers like Google and Meta affecting valuable insights.
This is precisely why CRO:NYX Digital approached us after discovering Google Analytics wasn’t providing accurate campaign data. We set up an analytics system to suit the company’s needs and tested it alongside Google Analytics for multiple campaigns. In one instance, Google Analytics failed to register 6,837 users in a single day, approximately 9.8% of the total tracked by Matomo.
In another instance, Google Analytics only tracked 600 visitors over 24 hours, while Matomo recorded nearly 71,000 visitors – an 11,700% discrepancy.
Financial companies need a more reliable, privacy-centric alternative to Google Analytics that captures quality data without putting users at potential risk. This is why we built Matomo and why our customers love having total control and visibility of their data.
Unlock the full power of fintech data analytics with Matomo
Fintech companies face many data-related challenges, so compliant web analytics shouldn’t be one of them.
With Matomo, you get :
- An all-in-one solution that handles traditional web analytics, behavioural analytics and more with strong integrations to minimise the likelihood of data siloing
- Full compliance with GDPR, CCPA, PIPL and more
- Complete ownership of your data to minimise cybersecurity risks caused by negligent third parties
- An abundance of ways to protect customer privacy, like IP address anonymisation and respect for DoNotTrack settings
- The ability to import data from Google Analytics and distance yourself from big tech
- High-quality data that doesn’t rely on sampling
- A tool built with financial analytics in mind
Don’t let big tech companies limit the power of your data with sketchy privacy policies and counterintuitive systems like data sampling.
Start your Matomo free trial or request a demo to unlock the full power of fintech data analytics without putting your customers’ personal information at unnecessary risk.
-
record mediasoup RTP stream using FFmpeg for Firefox
30 juillet 2024, par Hadi AghandehI am trying to record WebRTC stream using mediasoup. I could record successfully on chrome and safari 13/14/15. However on Firefox the does not work.


Client side code is a vue js component which gets rtp-compabilities using socket.io and create producers after the server creates the transports. This works good on chrome and safari.


const { connect , createLocalTracks } = require('twilio-video');
const SocketClient = require("socket.io-client");
const SocketPromise = require("socket.io-promise").default;
const MediasoupClient = require("mediasoup-client");

export default {
 data() {
 return {
 errors: [],
 isReady: false,
 isRecording: false,
 loading: false,
 sapio: {
 token: null,
 connectionId: 0
 },
 server: {
 host: 'https://rtc.test',
 ws: '/server',
 socket: null,
 },
 peer: {},
 }
 },
 mounted() {
 this.init();
 },
 methods: {
 async init() {
 await this.startCamera();

 if (this.takeId) {
 await this.recordBySapioServer();
 }
 },
 startCamera() {
 return new Promise( (resolve, reject) => {
 if (window.videoMediaStreamObject) {
 this.setVideoElementStream(window.videoMediaStreamObject);
 resolve();
 } else {
 // Get user media as required
 try {
 this.localeStream = navigator.mediaDevices.getUserMedia({
 audio: true,
 video: true,
 }).then((stream) => {
 this.setVideoElementStream(stream);
 resolve();
 })
 } catch (err) {
 console.error(err);
 reject();
 }
 }
 })
 },
 setVideoElementStream(stream) {
 this.localStream = stream;
 this.$refs.video.srcObject = stream;
 this.$refs.video.muted = true;
 this.$refs.video.play().then((video) => {
 this.isStreaming = true;
 this.height = this.$refs.video.videoHeight;
 this.width = this.$refs.video.videoWidth;
 });
 },
 // first thing we need is connecting to websocket
 connectToSocket() {
 const serverUrl = this.server.host;
 console.log("Connect with sapio rtc server:", serverUrl);

 const socket = SocketClient(serverUrl, {
 path: this.server.ws,
 transports: ["websocket"],
 });
 this.socket = socket;

 socket.on("connect", () => {
 console.log("WebSocket connected");
 // we ask for rtp-capabilities from server to send to us
 socket.emit('send-rtp-capabilities');
 });

 socket.on("error", (err) => {
 this.loading = true;
 console.error("WebSocket error:", err);
 });

 socket.on("router-rtp-capabilities", async (msg) => {
 const { routerRtpCapabilities, sessionId, externalId } = msg;
 console.log('[rtpCapabilities:%o]', routerRtpCapabilities);
 this.routerRtpCapabilities = routerRtpCapabilities;

 try {
 const device = new MediasoupClient.Device();
 // Load the mediasoup device with the router rtp capabilities gotten from the server
 await device.load({ routerRtpCapabilities });

 this.peer.sessionId = sessionId;
 this.peer.externalId = externalId;
 this.peer.device = device;

 this.createTransport();
 } catch (error) {
 console.error('failed to init device [error:%o]', error);
 socket.disconnect();
 }
 });

 socket.on("create-transport", async (msg) => {
 console.log('handleCreateTransportRequest() [data:%o]', msg);

 try {
 // Create the local mediasoup send transport
 this.peer.sendTransport = await this.peer.device.createSendTransport(msg);
 console.log('send transport created [id:%s]', this.peer.sendTransport.id);

 // Set the transport listeners and get the users media stream
 this.handleSendTransportListeners();
 this.setTracks();
 this.loading = false;
 } catch (error) {
 console.error('failed to create transport [error:%o]', error);
 socket.disconnect();
 }
 });

 socket.on("connect-transport", async (msg) => {
 console.log('handleTransportConnectRequest()');
 try {
 const action = this.connectTransport;

 if (!action) {
 throw new Error('transport-connect action was not found');
 }

 await action(msg);
 } catch (error) {
 console.error('ailed [error:%o]', error);
 }
 });

 socket.on("produce", async (msg) => {
 console.log('handleProduceRequest()');
 try {
 if (!this.produce) {
 throw new Error('produce action was not found');
 }
 await this.produce(msg);
 } catch (error) {
 console.error('failed [error:%o]', error);
 }
 });

 socket.on("recording", async (msg) => {
 this.isRecording = true;
 });

 socket.on("recording-error", async (msg) => {
 this.isRecording = false;
 console.error(msg);
 });

 socket.on("recording-closed", async (msg) => {
 this.isRecording = false;
 console.warn(msg)
 });

 },
 createTransport() {
 console.log('createTransport()');

 if (!this.peer || !this.peer.device.loaded) {
 throw new Error('Peer or device is not initialized');
 }

 // First we must create the mediasoup transport on the server side
 this.socket.emit('create-transport',{
 sessionId: this.peer.sessionId
 });
 },
 handleSendTransportListeners() {
 this.peer.sendTransport.on('connect', this.handleTransportConnectEvent);
 this.peer.sendTransport.on('produce', this.handleTransportProduceEvent);
 this.peer.sendTransport.on('connectionstatechange', connectionState => {
 console.log('send transport connection state change [state:%s]', connectionState);
 });
 },
 handleTransportConnectEvent({ dtlsParameters }, callback, errback) {
 console.log('handleTransportConnectEvent()');
 try {
 this.connectTransport = (msg) => {
 console.log('connect-transport action');
 callback();
 this.connectTransport = null;
 };

 this.socket.emit('connect-transport',{
 sessionId: this.peer.sessionId,
 transportId: this.peer.sendTransport.id,
 dtlsParameters
 });

 } catch (error) {
 console.error('handleTransportConnectEvent() failed [error:%o]', error);
 errback(error);
 }
 },
 handleTransportProduceEvent({ kind, rtpParameters }, callback, errback) {
 console.log('handleTransportProduceEvent()');
 try {
 this.produce = jsonMessage => {
 console.log('handleTransportProduceEvent callback [data:%o]', jsonMessage);
 callback({ id: jsonMessage.id });
 this.produce = null;
 };

 this.socket.emit('produce', {
 sessionId: this.peer.sessionId,
 transportId: this.peer.sendTransport.id,
 kind,
 rtpParameters
 });
 } catch (error) {
 console.error('handleTransportProduceEvent() failed [error:%o]', error);
 errback(error);
 }
 },
 async recordBySapioServer() {
 this.loading = true;
 this.connectToSocket();
 },
 async setTracks() {
 // Start mediasoup-client's WebRTC producers
 const audioTrack = this.localStream.getAudioTracks()[0];
 this.peer.audioProducer = await this.peer.sendTransport.produce({
 track: audioTrack,
 codecOptions :
 {
 opusStereo : 1,
 opusDtx : 1
 }
 });


 let encodings;
 let codec;
 const codecOptions = {videoGoogleStartBitrate : 1000};

 codec = this.peer.device.rtpCapabilities.codecs.find((c) => c.kind.toLowerCase() === 'video');
 if (codec.mimeType.toLowerCase() === 'video/vp9') {
 encodings = { scalabilityMode: 'S3T3_KEY' };
 } else {
 encodings = [
 { scaleResolutionDownBy: 4, maxBitrate: 500000 },
 { scaleResolutionDownBy: 2, maxBitrate: 1000000 },
 { scaleResolutionDownBy: 1, maxBitrate: 5000000 }
 ];
 }
 const videoTrack = this.localStream.getVideoTracks()[0];
 this.peer.videoProducer =await this.peer.sendTransport.produce({
 track: videoTrack,
 encodings,
 codecOptions,
 codec
 });

 },
 startRecording() {
 this.Q.answer.recordingId = this.peer.externalId;
 this.socket.emit("start-record", {
 sessionId: this.peer.sessionId
 });
 },
 stopRecording() {
 this.socket.emit("stop-record" , {
 sessionId: this.peer.sessionId
 });
 },
 },

}






console.log of my ffmpeg process :


// sdp string
[sdpString:v=0
 o=- 0 0 IN IP4 127.0.0.1
 s=FFmpeg
 c=IN IP4 127.0.0.1
 t=0 0
 m=video 25549 RTP/AVP 101 
 a=rtpmap:101 VP8/90000
 a=sendonly
 m=audio 26934 RTP/AVP 100 
 a=rtpmap:100 opus/48000/2
 a=sendonly
 ]

// ffmpeg args
commandArgs:[
 '-loglevel',
 'debug',
 '-protocol_whitelist',
 'pipe,udp,rtp',
 '-fflags',
 '+genpts',
 '-f',
 'sdp',
 '-i',
 'pipe:0',
 '-map',
 '0:v:0',
 '-c:v',
 'copy',
 '-map',
 '0:a:0',
 '-strict',
 '-2',
 '-c:a',
 'copy',
 '-f',
 'webm',
 '-flags',
 '+global_header',
 '-y',
 'storage/recordings/26e63cb3-4f81-499e-941a-c0bb7f7f52ce.webm',
 [length]: 26
]
// ffmpeg log
ffmpeg::process::data [data:'ffmpeg version n4.4']
ffmpeg::process::data [data:' Copyright (c) 2000-2021 the FFmpeg developers']
ffmpeg::process::data [data:'\n']
ffmpeg::process::data [data:' built with gcc 11.1.0 (GCC)\n']
ffmpeg::process::data [data:' configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-amf --enable-avisynth --enable-cuda-llvm --enable-lto --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmfx --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librav1e --enable-librsvg --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-libzimg --enable-nvdec --enable-nvenc --enable-shared --enable-version3\n']
ffmpeg::process::data [data:' libavutil 56. 70.100 / 56. 70.100\n' +
 ' libavcodec 58.134.100 / 58.134.100\n' +
 ' libavformat 58. 76.100 / 58. 76.100\n' +
 ' libavdevice 58. 13.100 / 58. 13.100\n' +
 ' libavfilter 7.110.100 / 7.110.100\n' +
 ' libswscale 5. 9.100 / 5. 9.100\n' +
 ' libswresample 3. 9.100 / 3. 9.100\n' +
 ' libpostproc 55. 9.100 / 55. 9.100\n' +
 'Splitting the commandline.\n' +
 "Reading option '-loglevel' ... matched as option 'loglevel' (set logging level) with argument 'debug'.\n" +
 "Reading option '-protocol_whitelist' ..."]
ffmpeg::process::data [data:" matched as AVOption 'protocol_whitelist' with argument 'pipe,udp,rtp'.\n" +
 "Reading option '-fflags' ..."]
ffmpeg::process::data [data:" matched as AVOption 'fflags' with argument '+genpts'.\n" +
 "Reading option '-f' ... matched as option 'f' (force format) with argument 'sdp'.\n" +
 "Reading option '-i' ... matched as input url with argument 'pipe:0'.\n" +
 "Reading option '-map' ... matched as option 'map' (set input stream mapping) with argument '0:v:0'.\n" +
 "Reading option '-c:v' ... matched as option 'c' (codec name) with argument 'copy'.\n" +
 "Reading option '-map' ... matched as option 'map' (set input stream mapping) with argument '0:a:0'.\n" +
 "Reading option '-strict' ...Routing option strict to both codec and muxer layer\n" +
 " matched as AVOption 'strict' with argument '-2'.\n" +
 "Reading option '-c:a' ... matched as option 'c' (codec name) with argument 'copy'.\n" +
 "Reading option '-f' ... matched as option 'f' (force format) with argument 'webm'.\n" +
 "Reading option '-flags' ... matched as AVOption 'flags' with argument '+global_header'.\n" +
 "Reading option '-y' ... matched as option 'y' (overwrite output files) with argument '1'.\n" +
 "Reading option 'storage/recordings/26e63cb3-4f81-499e-941a-c0bb7f7f52ce.webm' ... matched as output url.\n" +
 'Finished splitting the commandline.\n' +
 'Parsing a group of options: global .\n' +
 'Applying option loglevel (set logging level) with argument debug.\n' +
 'Applying option y (overwrite output files) with argument 1.\n' +
 'Successfully parsed a group of options.\n' +
 'Parsing a group of options: input url pipe:0.\n' +
 'Applying option f (force format) with argument sdp.\n' +
 'Successfully parsed a group of options.\n' +
 'Opening an input file: pipe:0.\n' +
 "[sdp @ 0x55604dc58400] Opening 'pipe:0' for reading\n" +
 '[sdp @ 0x55604dc58400] video codec set to: vp8\n' +
 '[sdp @ 0x55604dc58400] audio codec set to: opus\n' +
 '[sdp @ 0x55604dc58400] audio samplerate set to: 48000\n' +
 '[sdp @ 0x55604dc58400] audio channels set to: 2\n' +
 '[udp @ 0x55604dc6c500] end receive buffer size reported is 425984\n' +
 '[udp @ 0x55604dc6c7c0] end receive buffer size reported is 425984\n' +
 '[sdp @ 0x55604dc58400] setting jitter buffer size to 500\n' +
 '[udp @ 0x55604dc6d900] end receive buffer size reported is 425984\n' +
 '[udp @ 0x55604dc6d2c0] end receive buffer size reported is 425984\n' +
 '[sdp @ 0x55604dc58400] setting jitter buffer size to 500\n']
ffmpeg::process::data [data:'[sdp @ 0x55604dc58400] Before avformat_find_stream_info() pos: 210 bytes read:210 seeks:0 nb_streams:2\n']
 **mediasoup:Consumer resume() +1s**
 **mediasoup:Channel request() [method:consumer.resume, id:12] +1s**
 **mediasoup:Channel request succeeded [method:consumer.resume, id:12] +0ms**
 **mediasoup:Consumer resume() +1ms**
 **mediasoup:Channel request() [method:consumer.resume, id:13] +0ms**
 **mediasoup:Channel request succeeded [method:consumer.resume, id:13] +0ms**
ffmpeg::process::data [data:'[sdp @ 0x55604dc58400] Could not find codec parameters for stream 0 (Video: vp8, 1 reference frame, yuv420p): unspecified size\n' +
 "Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options\n"]
ffmpeg::process::data [data:'[sdp @ 0x55604dc58400] After avformat_find_stream_info() pos: 210 bytes read:210 seeks:0 frames:0\n' +
 "Input #0, sdp, from 'pipe:0':\n" +
 ' Metadata:\n' +
 ' title : FFmpeg\n' +
 ' Duration: N/A, bitrate: N/A\n' +
 ' Stream #0:0, 0, 1/90000: Video: vp8, 1 reference frame, yuv420p, 90k tbr, 90k tbn, 90k tbc\n' +
 ' Stream #0:1, 0, 1/48000: Audio: opus, 48000 Hz, stereo, fltp\n' +
 'Successfully opened the file.\n' +
 'Parsing a group of options: output url storage/recordings/26e63cb3-4f81-499e-941a-c0bb7f7f52ce.webm.\n' +
 'Applying option map (set input stream mapping) with argument 0:v:0.\n' +
 'Applying option c:v (codec name) with argument copy.\n' +
 'Applying option map (set input stream mapping) with argument 0:a:0.\n' +
 'Applying option c:a (codec name) with argument copy.\n' +
 'Applying option f (force format) with argument webm.\n' +
 'Successfully parsed a group of options.\n' +
 'Opening an output file: storage/recordings/26e63cb3-4f81-499e-941a-c0bb7f7f52ce.webm.\n' +
 "[file @ 0x55604dce5bc0] Setting default whitelist 'file,crypto,data'\n"]
ffmpeg::process::data [data:'Successfully opened the file.\n' +
 '[webm @ 0x55604dce0fc0] dimensions not set\n' +
 'Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument\n' +
 'Error initializing output stream 0:1 -- \n' +
 'Stream mapping:\n' +
 ' Stream #0:0 -> #0:0 (copy)\n' +
 ' Stream #0:1 -> #0:1 (copy)\n' +
 ' Last message repeated 1 times\n' +
 '[AVIOContext @ 0x55604dc6dcc0] Statistics: 0 seeks, 0 writeouts\n' +
 '[AVIOContext @ 0x55604dc69380] Statistics: 210 bytes read, 0 seeks\n']
ffmpeg::process::close




FFmpeg says
dimensions not set
andCould not write header for output file
when I use Firefox. This might be enough for understanding the problem, but if you need more information you can read how server side is performing.
Server-Side in summary can be something like this :
lets say we initialized worker and router at run time using following functions.

// Start the mediasoup workers
module.exports.initializeWorkers = async () => {
 const { logLevel, logTags, rtcMinPort, rtcMaxPort } = config.worker;

 console.log('initializeWorkers() creating %d mediasoup workers', config.numWorkers);

 for (let i = 0; i < config.numWorkers; ++i) {
 const worker = await mediasoup.createWorker({
 logLevel, logTags, rtcMinPort, rtcMaxPort
 });

 worker.once('died', () => {
 console.error('worker::died worker has died exiting in 2 seconds... [pid:%d]', worker.pid);
 setTimeout(() => process.exit(1), 2000);
 });

 workers.push(worker);
 }
};



module.exports.createRouter = async () => {
 const worker = getNextWorker();

 console.log('createRouter() creating new router [worker.pid:%d]', worker.pid);

 console.log(`config.router.mediaCodecs:${JSON.stringify(config.router.mediaCodecs)}`)

 return await worker.createRouter({ mediaCodecs: config.router.mediaCodecs });
};



We pass
router.rtpCompatibilities
to the client. clients get thertpCompatibilities
and create a device and loads it. after that a transport must be created at server side.

const handleCreateTransportRequest = async (jsonMessage) => {

 const transport = await createTransport('webRtc', router);

 var peer;
 try {peer = peers.get(jsonMessage.sessionId);}
 catch{console.log('peer not found')}
 
 peer.addTransport(transport);

 peer.socket.emit('create-transport',{
 id: transport.id,
 iceParameters: transport.iceParameters,
 iceCandidates: transport.iceCandidates,
 dtlsParameters: transport.dtlsParameters
 });
};



Then after the client side also created the transport we listen to connect event an at the time of event, we request the server to create connection.


const handleTransportConnectRequest = async (jsonMessage) => {
 var peer;
 try {peer = peers.get(jsonMessage.sessionId);}
 catch{console.log('peer not found')}

 if (!peer) {
 throw new Error(`Peer with id ${jsonMessage.sessionId} was not found`);
 }

 const transport = peer.getTransport(jsonMessage.transportId);

 if (!transport) {
 throw new Error(`Transport with id ${jsonMessage.transportId} was not found`);
 }

 await transport.connect({ dtlsParameters: jsonMessage.dtlsParameters });
 console.log('handleTransportConnectRequest() transport connected');
 peer.socket.emit('connect-transport');
};



Similar thing happen on produce event.


const handleProduceRequest = async (jsonMessage) => {
 console.log('handleProduceRequest [data:%o]', jsonMessage);

 var peer;
 try {peer = peers.get(jsonMessage.sessionId);}
 catch{console.log('peer not found')}

 if (!peer) {
 throw new Error(`Peer with id ${jsonMessage.sessionId} was not found`);
 }

 const transport = peer.getTransport(jsonMessage.transportId);

 if (!transport) {
 throw new Error(`Transport with id ${jsonMessage.transportId} was not found`);
 }

 const producer = await transport.produce({
 kind: jsonMessage.kind,
 rtpParameters: jsonMessage.rtpParameters
 });

 peer.addProducer(producer);

 console.log('handleProducerRequest() new producer added [id:%s, kind:%s]', producer.id, producer.kind);

 peer.socket.emit('produce',{
 id: producer.id,
 kind: producer.kind
 });
};



For Recording, first I create plain transports for audio and video producers.


const rtpTransport = router.createPlainTransport(config.plainRtpTransport);



then rtp transport must be connected to ports :


await rtpTransport.connect({
 ip: '127.0.0.1',
 port: remoteRtpPort,
 rtcpPort: remoteRtcpPort
 });



Then the consumer must also be created.


const rtpConsumer = await rtpTransport.consume({
 producerId: producer.id,
 rtpCapabilities,
 paused: true
 });



After that we can start recording using following code :


this._rtpParameters = args;
 this._process = undefined;
 this._observer = new EventEmitter();
 this._peer = args.peer;

 this._sdpString = createSdpText(this._rtpParameters);
 this._sdpStream = convertStringToStream(this._sdpString);
 // create dir
 const dir = process.env.REOCRDING_PATH ?? 'storage/recordings';
 if (!fs.existsSync(dir)) shelljs.mkdir('-p', dir);
 
 this._extension = 'webm';
 // create file path
 this._path = `${dir}/${args.peer.sessionId}.${this._extension}`
 let loop = 0;
 while(fs.existsSync(this._path)) {
 this._path = `${dir}/${args.peer.sessionId}-${++loop}.${this._extension}`
 }

this._recordingnModel = await Recording.findOne({sessionIds: { $in: [this._peer.sessionId] }})
 this._recordingnModel.files.push(this._path);
 this._recordingnModel.save();

let proc = ffmpeg(this._sdpStream)
 .inputOptions([
 '-protocol_whitelist','pipe,udp,rtp',
 '-f','sdp',
 ])
 .format(this._extension)
 .output(this._path)
 .size('720x?')
 .on('start', ()=>{
 this._peer.socket.emit('recording');
 })
 .on('end', ()=>{
 let path = this._path.replace('storage/recordings/', '');
 this._peer.socket.emit('recording-closed', {
 url: `${process.env.APP_URL}/recording/file/${path}`
 });
 });

 proc.run();
 this._process = proc;
 }




-
How to analyse 404 pages
1er juillet 2019, par Matomo Core Team — Development, Plugins