OLD | NEW |
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2004 Google Inc. | 3 * Copyright 2004 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
(...skipping 24 matching lines...) Expand all Loading... |
35 | 35 |
36 #include <algorithm> | 36 #include <algorithm> |
37 #include <cstdio> | 37 #include <cstdio> |
38 #include <string> | 38 #include <string> |
39 #include <vector> | 39 #include <vector> |
40 | 40 |
41 #include "talk/media/base/audioframe.h" | 41 #include "talk/media/base/audioframe.h" |
42 #include "talk/media/base/audiorenderer.h" | 42 #include "talk/media/base/audiorenderer.h" |
43 #include "talk/media/base/constants.h" | 43 #include "talk/media/base/constants.h" |
44 #include "talk/media/base/streamparams.h" | 44 #include "talk/media/base/streamparams.h" |
45 #include "talk/media/base/voiceprocessor.h" | |
46 #include "talk/media/webrtc/webrtcvoe.h" | 45 #include "talk/media/webrtc/webrtcvoe.h" |
47 #include "webrtc/base/base64.h" | 46 #include "webrtc/base/base64.h" |
48 #include "webrtc/base/byteorder.h" | 47 #include "webrtc/base/byteorder.h" |
49 #include "webrtc/base/common.h" | 48 #include "webrtc/base/common.h" |
50 #include "webrtc/base/helpers.h" | 49 #include "webrtc/base/helpers.h" |
51 #include "webrtc/base/logging.h" | 50 #include "webrtc/base/logging.h" |
52 #include "webrtc/base/stringencode.h" | 51 #include "webrtc/base/stringencode.h" |
53 #include "webrtc/base/stringutils.h" | 52 #include "webrtc/base/stringutils.h" |
54 #include "webrtc/common.h" | 53 #include "webrtc/common.h" |
55 #include "webrtc/modules/audio_processing/include/audio_processing.h" | 54 #include "webrtc/modules/audio_processing/include/audio_processing.h" |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 | 360 |
362 static std::string GetEnableString(bool enable) { | 361 static std::string GetEnableString(bool enable) { |
363 return enable ? "enable" : "disable"; | 362 return enable ? "enable" : "disable"; |
364 } | 363 } |
365 | 364 |
366 WebRtcVoiceEngine::WebRtcVoiceEngine() | 365 WebRtcVoiceEngine::WebRtcVoiceEngine() |
367 : voe_wrapper_(new VoEWrapper()), | 366 : voe_wrapper_(new VoEWrapper()), |
368 tracing_(new VoETraceWrapper()), | 367 tracing_(new VoETraceWrapper()), |
369 adm_(NULL), | 368 adm_(NULL), |
370 log_filter_(SeverityToFilter(kDefaultLogSeverity)), | 369 log_filter_(SeverityToFilter(kDefaultLogSeverity)), |
371 is_dumping_aec_(false), | 370 is_dumping_aec_(false) { |
372 tx_processor_ssrc_(0), | |
373 rx_processor_ssrc_(0) { | |
374 Construct(); | 371 Construct(); |
375 } | 372 } |
376 | 373 |
377 WebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper, | 374 WebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper, |
378 VoETraceWrapper* tracing) | 375 VoETraceWrapper* tracing) |
379 : voe_wrapper_(voe_wrapper), | 376 : voe_wrapper_(voe_wrapper), |
380 tracing_(tracing), | 377 tracing_(tracing), |
381 adm_(NULL), | 378 adm_(NULL), |
382 log_filter_(SeverityToFilter(kDefaultLogSeverity)), | 379 log_filter_(SeverityToFilter(kDefaultLogSeverity)), |
383 is_dumping_aec_(false), | 380 is_dumping_aec_(false) { |
384 tx_processor_ssrc_(0), | |
385 rx_processor_ssrc_(0) { | |
386 Construct(); | 381 Construct(); |
387 } | 382 } |
388 | 383 |
389 void WebRtcVoiceEngine::Construct() { | 384 void WebRtcVoiceEngine::Construct() { |
390 SetTraceFilter(log_filter_); | 385 SetTraceFilter(log_filter_); |
391 initialized_ = false; | 386 initialized_ = false; |
392 LOG(LS_VERBOSE) << "WebRtcVoiceEngine::WebRtcVoiceEngine"; | 387 LOG(LS_VERBOSE) << "WebRtcVoiceEngine::WebRtcVoiceEngine"; |
393 SetTraceOptions(""); | 388 SetTraceOptions(""); |
394 if (tracing_->SetTraceCallback(this) == -1) { | 389 if (tracing_->SetTraceCallback(this) == -1) { |
395 LOG_RTCERR0(SetTraceCallback); | 390 LOG_RTCERR0(SetTraceCallback); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 LOG(LS_VERBOSE) << "WebRtcVoiceEngine::~WebRtcVoiceEngine"; | 478 LOG(LS_VERBOSE) << "WebRtcVoiceEngine::~WebRtcVoiceEngine"; |
484 if (voe_wrapper_->base()->DeRegisterVoiceEngineObserver() == -1) { | 479 if (voe_wrapper_->base()->DeRegisterVoiceEngineObserver() == -1) { |
485 LOG_RTCERR0(DeRegisterVoiceEngineObserver); | 480 LOG_RTCERR0(DeRegisterVoiceEngineObserver); |
486 } | 481 } |
487 if (adm_) { | 482 if (adm_) { |
488 voe_wrapper_.reset(); | 483 voe_wrapper_.reset(); |
489 adm_->Release(); | 484 adm_->Release(); |
490 adm_ = NULL; | 485 adm_ = NULL; |
491 } | 486 } |
492 | 487 |
493 // Test to see if the media processor was deregistered properly | |
494 RTC_DCHECK(SignalRxMediaFrame.is_empty()); | |
495 RTC_DCHECK(SignalTxMediaFrame.is_empty()); | |
496 | |
497 tracing_->SetTraceCallback(NULL); | 488 tracing_->SetTraceCallback(NULL); |
498 } | 489 } |
499 | 490 |
500 bool WebRtcVoiceEngine::Init(rtc::Thread* worker_thread) { | 491 bool WebRtcVoiceEngine::Init(rtc::Thread* worker_thread) { |
501 RTC_DCHECK(worker_thread == rtc::Thread::Current()); | 492 RTC_DCHECK(worker_thread == rtc::Thread::Current()); |
502 LOG(LS_INFO) << "WebRtcVoiceEngine::Init"; | 493 LOG(LS_INFO) << "WebRtcVoiceEngine::Init"; |
503 bool res = InitInternal(); | 494 bool res = InitInternal(); |
504 if (res) { | 495 if (res) { |
505 LOG(LS_INFO) << "WebRtcVoiceEngine::Init Done!"; | 496 LOG(LS_INFO) << "WebRtcVoiceEngine::Init Done!"; |
506 } else { | 497 } else { |
(...skipping 763 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1270 RTC_DCHECK(ch != NULL); | 1261 RTC_DCHECK(ch != NULL); |
1271 if (ch->FindSsrc(channel_num, ssrc)) { | 1262 if (ch->FindSsrc(channel_num, ssrc)) { |
1272 *channel = ch; | 1263 *channel = ch; |
1273 return true; | 1264 return true; |
1274 } | 1265 } |
1275 } | 1266 } |
1276 | 1267 |
1277 return false; | 1268 return false; |
1278 } | 1269 } |
1279 | 1270 |
1280 // This method will search through the WebRtcVoiceMediaChannels and | |
1281 // obtain the voice engine's channel number. | |
1282 bool WebRtcVoiceEngine::FindChannelNumFromSsrc( | |
1283 uint32 ssrc, MediaProcessorDirection direction, int* channel_num) { | |
1284 RTC_DCHECK(channel_num != NULL); | |
1285 RTC_DCHECK(direction == MPD_RX || direction == MPD_TX); | |
1286 | |
1287 *channel_num = -1; | |
1288 // Find corresponding channel for ssrc. | |
1289 for (const WebRtcVoiceMediaChannel* ch : channels_) { | |
1290 RTC_DCHECK(ch != NULL); | |
1291 if (direction & MPD_RX) { | |
1292 *channel_num = ch->GetReceiveChannelNum(ssrc); | |
1293 } | |
1294 if (*channel_num == -1 && (direction & MPD_TX)) { | |
1295 *channel_num = ch->GetSendChannelNum(ssrc); | |
1296 } | |
1297 if (*channel_num != -1) { | |
1298 return true; | |
1299 } | |
1300 } | |
1301 LOG(LS_WARNING) << "FindChannelFromSsrc. No Channel Found for Ssrc: " << ssrc; | |
1302 return false; | |
1303 } | |
1304 | |
1305 void WebRtcVoiceEngine::RegisterChannel(WebRtcVoiceMediaChannel *channel) { | 1271 void WebRtcVoiceEngine::RegisterChannel(WebRtcVoiceMediaChannel *channel) { |
1306 rtc::CritScope lock(&channels_cs_); | 1272 rtc::CritScope lock(&channels_cs_); |
1307 channels_.push_back(channel); | 1273 channels_.push_back(channel); |
1308 } | 1274 } |
1309 | 1275 |
1310 void WebRtcVoiceEngine::UnregisterChannel(WebRtcVoiceMediaChannel *channel) { | 1276 void WebRtcVoiceEngine::UnregisterChannel(WebRtcVoiceMediaChannel *channel) { |
1311 rtc::CritScope lock(&channels_cs_); | 1277 rtc::CritScope lock(&channels_cs_); |
1312 ChannelList::iterator i = std::find(channels_.begin(), | 1278 ChannelList::iterator i = std::find(channels_.begin(), |
1313 channels_.end(), | 1279 channels_.end(), |
1314 channel); | 1280 channel); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1363 if (voe_wrapper_->processing()->StartDebugRecording(aec_dump_file_stream) != | 1329 if (voe_wrapper_->processing()->StartDebugRecording(aec_dump_file_stream) != |
1364 webrtc::AudioProcessing::kNoError) { | 1330 webrtc::AudioProcessing::kNoError) { |
1365 LOG_RTCERR0(StartDebugRecording); | 1331 LOG_RTCERR0(StartDebugRecording); |
1366 fclose(aec_dump_file_stream); | 1332 fclose(aec_dump_file_stream); |
1367 return false; | 1333 return false; |
1368 } | 1334 } |
1369 is_dumping_aec_ = true; | 1335 is_dumping_aec_ = true; |
1370 return true; | 1336 return true; |
1371 } | 1337 } |
1372 | 1338 |
1373 bool WebRtcVoiceEngine::RegisterProcessor( | |
1374 uint32 ssrc, | |
1375 VoiceProcessor* voice_processor, | |
1376 MediaProcessorDirection direction) { | |
1377 bool register_with_webrtc = false; | |
1378 int channel_id = -1; | |
1379 bool success = false; | |
1380 uint32* processor_ssrc = NULL; | |
1381 bool found_channel = FindChannelNumFromSsrc(ssrc, direction, &channel_id); | |
1382 if (voice_processor == NULL || !found_channel) { | |
1383 LOG(LS_WARNING) << "Media Processing Registration Failed. ssrc: " << ssrc | |
1384 << " foundChannel: " << found_channel; | |
1385 return false; | |
1386 } | |
1387 | |
1388 webrtc::ProcessingTypes processing_type; | |
1389 { | |
1390 rtc::CritScope cs(&signal_media_critical_); | |
1391 if (direction == MPD_RX) { | |
1392 processing_type = webrtc::kPlaybackAllChannelsMixed; | |
1393 if (SignalRxMediaFrame.is_empty()) { | |
1394 register_with_webrtc = true; | |
1395 processor_ssrc = &rx_processor_ssrc_; | |
1396 } | |
1397 SignalRxMediaFrame.connect(voice_processor, | |
1398 &VoiceProcessor::OnFrame); | |
1399 } else { | |
1400 processing_type = webrtc::kRecordingPerChannel; | |
1401 if (SignalTxMediaFrame.is_empty()) { | |
1402 register_with_webrtc = true; | |
1403 processor_ssrc = &tx_processor_ssrc_; | |
1404 } | |
1405 SignalTxMediaFrame.connect(voice_processor, | |
1406 &VoiceProcessor::OnFrame); | |
1407 } | |
1408 } | |
1409 if (register_with_webrtc) { | |
1410 // TODO(janahan): when registering consider instantiating a | |
1411 // a VoeMediaProcess object and not make the engine extend the interface. | |
1412 if (voe()->media() && voe()->media()-> | |
1413 RegisterExternalMediaProcessing(channel_id, | |
1414 processing_type, | |
1415 *this) != -1) { | |
1416 LOG(LS_INFO) << "Media Processing Registration Succeeded. channel:" | |
1417 << channel_id; | |
1418 *processor_ssrc = ssrc; | |
1419 success = true; | |
1420 } else { | |
1421 LOG_RTCERR2(RegisterExternalMediaProcessing, | |
1422 channel_id, | |
1423 processing_type); | |
1424 success = false; | |
1425 } | |
1426 } else { | |
1427 // If we don't have to register with the engine, we just needed to | |
1428 // connect a new processor, set success to true; | |
1429 success = true; | |
1430 } | |
1431 return success; | |
1432 } | |
1433 | |
1434 bool WebRtcVoiceEngine::UnregisterProcessorChannel( | |
1435 MediaProcessorDirection channel_direction, | |
1436 uint32 ssrc, | |
1437 VoiceProcessor* voice_processor, | |
1438 MediaProcessorDirection processor_direction) { | |
1439 bool success = true; | |
1440 FrameSignal* signal; | |
1441 webrtc::ProcessingTypes processing_type; | |
1442 uint32* processor_ssrc = NULL; | |
1443 if (channel_direction == MPD_RX) { | |
1444 signal = &SignalRxMediaFrame; | |
1445 processing_type = webrtc::kPlaybackAllChannelsMixed; | |
1446 processor_ssrc = &rx_processor_ssrc_; | |
1447 } else { | |
1448 signal = &SignalTxMediaFrame; | |
1449 processing_type = webrtc::kRecordingPerChannel; | |
1450 processor_ssrc = &tx_processor_ssrc_; | |
1451 } | |
1452 | |
1453 int deregister_id = -1; | |
1454 { | |
1455 rtc::CritScope cs(&signal_media_critical_); | |
1456 if ((processor_direction & channel_direction) != 0 && !signal->is_empty()) { | |
1457 signal->disconnect(voice_processor); | |
1458 int channel_id = -1; | |
1459 bool found_channel = FindChannelNumFromSsrc(ssrc, | |
1460 channel_direction, | |
1461 &channel_id); | |
1462 if (signal->is_empty() && found_channel) { | |
1463 deregister_id = channel_id; | |
1464 } | |
1465 } | |
1466 } | |
1467 if (deregister_id != -1) { | |
1468 if (voe()->media() && | |
1469 voe()->media()->DeRegisterExternalMediaProcessing(deregister_id, | |
1470 processing_type) != -1) { | |
1471 *processor_ssrc = 0; | |
1472 LOG(LS_INFO) << "Media Processing DeRegistration Succeeded. channel:" | |
1473 << deregister_id; | |
1474 } else { | |
1475 LOG_RTCERR2(DeRegisterExternalMediaProcessing, | |
1476 deregister_id, | |
1477 processing_type); | |
1478 success = false; | |
1479 } | |
1480 } | |
1481 return success; | |
1482 } | |
1483 | |
1484 bool WebRtcVoiceEngine::UnregisterProcessor( | |
1485 uint32 ssrc, | |
1486 VoiceProcessor* voice_processor, | |
1487 MediaProcessorDirection direction) { | |
1488 bool success = true; | |
1489 if (voice_processor == NULL) { | |
1490 LOG(LS_WARNING) << "Media Processing Deregistration Failed. ssrc: " | |
1491 << ssrc; | |
1492 return false; | |
1493 } | |
1494 if (!UnregisterProcessorChannel(MPD_RX, ssrc, voice_processor, direction)) { | |
1495 success = false; | |
1496 } | |
1497 if (!UnregisterProcessorChannel(MPD_TX, ssrc, voice_processor, direction)) { | |
1498 success = false; | |
1499 } | |
1500 return success; | |
1501 } | |
1502 | |
1503 // Implementing method from WebRtc VoEMediaProcess interface | |
1504 // Do not lock mux_channel_cs_ in this callback. | |
1505 void WebRtcVoiceEngine::Process(int channel, | |
1506 webrtc::ProcessingTypes type, | |
1507 int16_t audio10ms[], | |
1508 size_t length, | |
1509 int sampling_freq, | |
1510 bool is_stereo) { | |
1511 rtc::CritScope cs(&signal_media_critical_); | |
1512 AudioFrame frame(audio10ms, length, sampling_freq, is_stereo); | |
1513 if (type == webrtc::kPlaybackAllChannelsMixed) { | |
1514 SignalRxMediaFrame(rx_processor_ssrc_, MPD_RX, &frame); | |
1515 } else if (type == webrtc::kRecordingPerChannel) { | |
1516 SignalTxMediaFrame(tx_processor_ssrc_, MPD_TX, &frame); | |
1517 } else { | |
1518 LOG(LS_WARNING) << "Media Processing invoked unexpectedly." | |
1519 << " channel: " << channel << " type: " << type | |
1520 << " tx_ssrc: " << tx_processor_ssrc_ | |
1521 << " rx_ssrc: " << rx_processor_ssrc_; | |
1522 } | |
1523 } | |
1524 | |
1525 void WebRtcVoiceEngine::StartAecDump(const std::string& filename) { | 1339 void WebRtcVoiceEngine::StartAecDump(const std::string& filename) { |
1526 if (!is_dumping_aec_) { | 1340 if (!is_dumping_aec_) { |
1527 // Start dumping AEC when we are not dumping. | 1341 // Start dumping AEC when we are not dumping. |
1528 if (voe_wrapper_->processing()->StartDebugRecording( | 1342 if (voe_wrapper_->processing()->StartDebugRecording( |
1529 filename.c_str()) != webrtc::AudioProcessing::kNoError) { | 1343 filename.c_str()) != webrtc::AudioProcessing::kNoError) { |
1530 LOG_RTCERR1(StartDebugRecording, filename.c_str()); | 1344 LOG_RTCERR1(StartDebugRecording, filename.c_str()); |
1531 } else { | 1345 } else { |
1532 is_dumping_aec_ = true; | 1346 is_dumping_aec_ = true; |
1533 } | 1347 } |
1534 } | 1348 } |
(...skipping 1959 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3494 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); | 3308 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); |
3495 return false; | 3309 return false; |
3496 } | 3310 } |
3497 } | 3311 } |
3498 return true; | 3312 return true; |
3499 } | 3313 } |
3500 | 3314 |
3501 } // namespace cricket | 3315 } // namespace cricket |
3502 | 3316 |
3503 #endif // HAVE_WEBRTC_VOICE | 3317 #endif // HAVE_WEBRTC_VOICE |
OLD | NEW |