diff options
Diffstat (limited to 'src/components/media_manager/src/audio')
7 files changed, 1005 insertions, 0 deletions
diff --git a/src/components/media_manager/src/audio/a2dp_source_player_adapter.cc b/src/components/media_manager/src/audio/a2dp_source_player_adapter.cc new file mode 100644 index 0000000000..91604d22c9 --- /dev/null +++ b/src/components/media_manager/src/audio/a2dp_source_player_adapter.cc @@ -0,0 +1,278 @@ +/** +* Copyright (c) 2013, Ford Motor Company +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the +* distribution. +* +* Neither the name of the Ford Motor Company nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ +#include <net/if.h> +#include <pulse/simple.h> +#include <pulse/error.h> +#include <string.h> +#include <utility> +#include "utils/threads/thread.h" +#include "media_manager/audio/a2dp_source_player_adapter.h" +#include "utils/lock.h" +#include "utils/threads/thread_delegate.h" +#include "utils/logger.h" +#include "connection_handler/connection_handler_impl.h" + +namespace media_manager { + +CREATE_LOGGERPTR_GLOBAL(logger_, "A2DPSourcePlayerAdapter") + +class A2DPSourcePlayerAdapter::A2DPSourcePlayerThread + : public threads::ThreadDelegate { + public: + explicit A2DPSourcePlayerThread(const std::string& device); + + void threadMain(); + + bool exitThreadMain(); + + private: + // The Sample format to use + static const pa_sample_spec sSampleFormat_; + + pa_simple* s_in, *s_out; + std::string device_; + const int32_t BUFSIZE_; + bool should_be_stopped_; + sync_primitives::Lock should_be_stopped_lock_; + + void freeStreams(); + + DISALLOW_COPY_AND_ASSIGN(A2DPSourcePlayerThread); +}; + +A2DPSourcePlayerAdapter::A2DPSourcePlayerAdapter() { +} + +A2DPSourcePlayerAdapter::~A2DPSourcePlayerAdapter() { + for (std::map<int32_t, threads::Thread*>::iterator it = sources_.begin(); + sources_.end() != it; + ++it) { + if (NULL != it->second) { + if (it->second->is_running()) { + it->second->stop(); + } + delete(it->second); + } + } + sources_.clear(); +} + +void A2DPSourcePlayerAdapter::StartActivity(int32_t application_key) { + LOG4CXX_INFO(logger_, "Starting a2dp playing music for " + << application_key << " application."); + if (application_key != current_application_) { + current_application_ = application_key; + + std::map<int32_t, threads::Thread*>::iterator it = + sources_.find(application_key); + if (sources_.end() != it) { + if (NULL != it->second && !it->second->is_running()) { + it->second->start(); + } else { + current_application_ = 0; + } + } else { + uint32_t device_id = 0; + connection_handler::ConnectionHandlerImpl::instance()-> + GetDataOnSessionKey(application_key, 0, NULL, &device_id); + std::string mac_adddress; + connection_handler::ConnectionHandlerImpl::instance()->GetDataOnDeviceID( + device_id, + NULL, + NULL, + &mac_adddress); + + // TODO(PK): Convert mac_adddress to the + // following format : "bluez_source.XX_XX_XX_XX_XX_XX" if needed + // before passing to the A2DPSourcePlayerThread constructor + + threads::Thread* new_activity = new threads::Thread( + mac_adddress.c_str(), + new A2DPSourcePlayerAdapter::A2DPSourcePlayerThread(mac_adddress)); + if (NULL != new_activity) { + sources_.insert(std::pair<int32_t, threads::Thread*>( + application_key, new_activity)); + + new_activity->start(); + } else { + current_application_ = 0; + } + } + } +} + +void A2DPSourcePlayerAdapter::StopActivity(int32_t application_key) { + LOG4CXX_INFO(logger_, "Stopping 2dp playing for " + << application_key << " application."); + if (application_key != current_application_) { + return; + } + std::map<int32_t, threads::Thread*>::iterator it = + sources_.find(application_key); + if (sources_.end() != it) { + LOG4CXX_DEBUG(logger_, "Source exists."); + if (NULL != it->second) { + LOG4CXX_DEBUG(logger_, "Sources thread was allocated"); + if ((*it).second->is_running()) { + // Sources thread was started - stop it + LOG4CXX_DEBUG(logger_, "Sources thread was started - stop it"); + (*it).second->stop(); + } + } + current_application_ = 0; + } +} + +bool A2DPSourcePlayerAdapter::is_app_performing_activity(int32_t + application_key) { + return (application_key == current_application_); +} + +const pa_sample_spec A2DPSourcePlayerAdapter::A2DPSourcePlayerThread:: +sSampleFormat_ = { + /*format*/ PA_SAMPLE_S16LE, + /*rate*/ 44100, + /*channels*/ 2 +}; + +A2DPSourcePlayerAdapter::A2DPSourcePlayerThread::A2DPSourcePlayerThread( + const std::string& device) + : threads::ThreadDelegate(), + device_(device), + BUFSIZE_(32) { +} + +void A2DPSourcePlayerAdapter::A2DPSourcePlayerThread::freeStreams() { + LOG4CXX_INFO(logger_, "Free streams in A2DPSourcePlayerThread."); + if (s_in) { + pa_simple_free(s_in); + } + + if (s_out) { + pa_simple_free(s_out); + } +} + +bool A2DPSourcePlayerAdapter::A2DPSourcePlayerThread::exitThreadMain() { + sync_primitives::AutoLock auto_lock(should_be_stopped_lock_); + should_be_stopped_ = true; + return true; +} + +void A2DPSourcePlayerAdapter::A2DPSourcePlayerThread::threadMain() { + LOG4CXX_INFO(logger_, "Main thread of A2DPSourcePlayerThread."); + + { + sync_primitives::AutoLock auto_lock(should_be_stopped_lock_); + should_be_stopped_ = false; + } + + int32_t error; + + const char* a2dpSource = device_.c_str(); + + LOG4CXX_DEBUG(logger_, device_); + + LOG4CXX_DEBUG(logger_, "Creating streams"); + + /* Create a new playback stream */ + if (!(s_out = pa_simple_new(NULL, "AudioManager", PA_STREAM_PLAYBACK, NULL, + "playback", &sSampleFormat_, NULL, NULL, &error))) { + LOG4CXX_ERROR(logger_, "pa_simple_new() failed: " << pa_strerror(error)); + freeStreams(); + return; + } + + if (!(s_in = pa_simple_new(NULL, "AudioManager", PA_STREAM_RECORD, a2dpSource, + "record", &sSampleFormat_, NULL, NULL, &error))) { + LOG4CXX_ERROR(logger_, "pa_simple_new() failed: " << pa_strerror(error)); + freeStreams(); + return; + } + + LOG4CXX_DEBUG(logger_, "Entering main loop"); + + for (;;) { + uint8_t buf[BUFSIZE_]; + + pa_usec_t latency; + + if ((latency = pa_simple_get_latency(s_in, &error)) == (pa_usec_t) - 1) { + LOG4CXX_ERROR(logger_, "pa_simple_get_latency() failed: " + << pa_strerror(error)); + break; + } + + // LOG4CXX_INFO(logger_, "In: " << static_cast<float>(latency)); + + if ((latency = pa_simple_get_latency(s_out, &error)) == (pa_usec_t) - 1) { + LOG4CXX_ERROR(logger_, "pa_simple_get_latency() failed: " + << pa_strerror(error)); + break; + } + + // LOG4CXX_INFO(logger_, "Out: " << static_cast<float>(latency)); + + if (pa_simple_read(s_in, buf, sizeof(buf), &error) < 0) { + LOG4CXX_ERROR(logger_, "read() failed: " << strerror(error)); + break; + } + + /* ... and play it */ + if (pa_simple_write(s_out, buf, sizeof(buf), &error) < 0) { + LOG4CXX_ERROR(logger_, "pa_simple_write() failed: " + << pa_strerror(error)); + break; + } + + bool should_be_stopped; + { + sync_primitives::AutoLock auto_lock(should_be_stopped_lock_); + should_be_stopped = should_be_stopped_; + } + + if (should_be_stopped) { + break; + } + } + + /* Make sure that every single sample was played */ + if (pa_simple_drain(s_out, &error) < 0) { + LOG4CXX_ERROR(logger_, "pa_simple_drain() failed: " << pa_strerror(error)); + freeStreams(); + return; + } + + freeStreams(); +} + +} // namespace media_manager diff --git a/src/components/media_manager/src/audio/audio_stream_sender_thread.cc b/src/components/media_manager/src/audio/audio_stream_sender_thread.cc new file mode 100644 index 0000000000..a3ef5af0bf --- /dev/null +++ b/src/components/media_manager/src/audio/audio_stream_sender_thread.cc @@ -0,0 +1,149 @@ +// +// Copyright (c) 2013, Ford Motor Company +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following +// disclaimer in the documentation and/or other materials provided with the +// distribution. +// +// Neither the name of the Ford Motor Company nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// + + +#if defined(OS_POSIX) && defined(OS_LINUX) +#include <pthread.h> // TODO(DK): Need to remove +#include <unistd.h> +#endif + + +#include <string> +#include "application_manager/application_manager_impl.h" +#include "application_manager/mobile_command_factory.h" +#include "application_manager/application_impl.h" +#include "smart_objects/smart_object.h" +#include "interfaces/MOBILE_API.h" +#include "utils/file_system.h" +#include "utils/logger.h" + +#include "media_manager/audio/audio_stream_sender_thread.h" +#include "application_manager/smart_object_keys.h" +#include "application_manager/message.h" + +namespace media_manager { +using sync_primitives::AutoLock; + +const int32_t AudioStreamSenderThread::kAudioPassThruTimeout = 1; +const uint32_t kMqueueMessageSize = 4095; + +CREATE_LOGGERPTR_GLOBAL(logger_, "AudioPassThruThread") + +AudioStreamSenderThread::AudioStreamSenderThread( + const std::string fileName, uint32_t session_key) + : session_key_(session_key), + fileName_(fileName), + shouldBeStoped_(false), + shouldBeStoped_lock_(), + shouldBeStoped_cv_() { + LOG4CXX_TRACE_ENTER(logger_); +} + +AudioStreamSenderThread::~AudioStreamSenderThread() { +} + +void AudioStreamSenderThread::threadMain() { + LOG4CXX_TRACE_ENTER(logger_); + + offset_ = 0; + + while (false == getShouldBeStopped()) { + AutoLock auto_lock(shouldBeStoped_lock_); + shouldBeStoped_cv_.WaitFor(auto_lock, kAudioPassThruTimeout * 1000); + sendAudioChunkToMobile(); + } + + LOG4CXX_TRACE_EXIT(logger_); +} + +void AudioStreamSenderThread::sendAudioChunkToMobile() { + LOG4CXX_TRACE_ENTER(logger_); + + std::vector<uint8_t> binaryData; + std::vector<uint8_t>::iterator from; + std::vector<uint8_t>::iterator to; + + if (!file_system::ReadBinaryFile(fileName_, binaryData)) { + LOG4CXX_ERROR_EXT(logger_, "Unable to read file." << fileName_); + + return; + } + + if (binaryData.empty()) { + LOG4CXX_ERROR_EXT(logger_, "Binary data is empty."); + return; + } + + LOG4CXX_INFO_EXT(logger_, "offset = " << offset_); + + from = binaryData.begin() + offset_; + to = binaryData.end(); + + if (from < binaryData.end() /*from != binaryData.end()*/) { + LOG4CXX_INFO_EXT(logger_, "from != binaryData.end()"); + + offset_ = offset_ + to - from; + + application_manager::ApplicationManagerImpl::instance()-> + SendAudioPassThroughNotification(session_key_, + std::vector<uint8_t>(from, to)); + binaryData.clear(); + } +#if !defined(EXTENDED_MEDIA_MODE) + // without recording stream restart reading 1-sec file + offset_ = 0; +#endif +} + +bool AudioStreamSenderThread::getShouldBeStopped() { + AutoLock auto_lock(shouldBeStoped_lock_); + + return shouldBeStoped_; +} + +void AudioStreamSenderThread::setShouldBeStopped(bool should_stop) { + AutoLock auto_lock(shouldBeStoped_lock_); + shouldBeStoped_ = should_stop; + shouldBeStoped_cv_.NotifyOne(); +} + +bool AudioStreamSenderThread::exitThreadMain() { + LOG4CXX_INFO(logger_, "AudioStreamSenderThread::exitThreadMain"); + setShouldBeStopped(true); + return true; +} + +uint32_t AudioStreamSenderThread::session_key() const { + return session_key_; +} + +} // namespace media_manager diff --git a/src/components/media_manager/src/audio/from_mic_recorder_adapter.cc b/src/components/media_manager/src/audio/from_mic_recorder_adapter.cc new file mode 100644 index 0000000000..ba5e7ec54a --- /dev/null +++ b/src/components/media_manager/src/audio/from_mic_recorder_adapter.cc @@ -0,0 +1,110 @@ +/** +* Copyright (c) 2013, Ford Motor Company +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the +* distribution. +* +* Neither the name of the Ford Motor Company nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <string> +#include "utils/threads/thread.h" +#include "utils/logger.h" +#include "media_manager/audio/from_mic_to_file_recorder_thread.h" +#include "media_manager/audio/from_mic_recorder_adapter.h" + +namespace media_manager { + +CREATE_LOGGERPTR_GLOBAL(logger_, "FromMicRecorderAdapter") + +FromMicRecorderAdapter::FromMicRecorderAdapter() + : recorder_thread_(NULL) + , output_file_("default_recorded_audio.wav") + , kDefaultDuration(1000) + , duration_(0) { + duration_ = kDefaultDuration; +} + +FromMicRecorderAdapter::~FromMicRecorderAdapter() { + LOG4CXX_INFO(logger_, "FromMicRecorderAdapter::~FromMicRecorderAdapter()"); + StopActivity(current_application_); +} + +void FromMicRecorderAdapter::StartActivity(int32_t application_key) { + LOG4CXX_INFO(logger_, "FromMicRecorderAdapter::StartActivity " + << application_key); + if (application_key == current_application_) { + LOG4CXX_WARN(logger_, "Running recording from mic for " + << current_application_); + return; + } + +// Todd: No gstreamer recorder thread + if (!recorder_thread_) { + FromMicToFileRecorderThread* thread_delegate = + new FromMicToFileRecorderThread( + output_file_, duration_); + recorder_thread_ = new threads::Thread("MicrophoneRec", + thread_delegate); + } + + if (NULL != recorder_thread_) { + recorder_thread_->start(); + current_application_ = application_key; + } +} + +void FromMicRecorderAdapter::StopActivity(int32_t application_key) { + LOG4CXX_INFO(logger_, "FromMicRecorderAdapter::StopActivity " + << application_key); + if (application_key != current_application_) { + LOG4CXX_WARN(logger_, "Running activity on other app key " + << current_application_); + return; + } + + if (NULL != recorder_thread_) { + recorder_thread_->stop(); + delete recorder_thread_; + recorder_thread_ = NULL; + } + current_application_ = 0; +} + +bool FromMicRecorderAdapter::is_app_performing_activity(int32_t + application_key) { + return (application_key == current_application_); +} + +void FromMicRecorderAdapter::set_output_file(const std::string& output_file) { + output_file_ = output_file; +} + +void FromMicRecorderAdapter::set_duration(int32_t duration) { + duration_ = duration; +} + +} // namespace media_manager diff --git a/src/components/media_manager/src/audio/from_mic_recorder_listener.cc b/src/components/media_manager/src/audio/from_mic_recorder_listener.cc new file mode 100644 index 0000000000..cec85ca4e6 --- /dev/null +++ b/src/components/media_manager/src/audio/from_mic_recorder_listener.cc @@ -0,0 +1,99 @@ +/* + Copyright (c) 2013, Ford Motor Company + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following + disclaimer in the documentation and/or other materials provided with the + distribution. + + Neither the name of the Ford Motor Company nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#include "utils/threads/thread.h" +#include "utils/logger.h" +#include "media_manager/audio/from_mic_recorder_listener.h" +#include "media_manager/audio/audio_stream_sender_thread.h" + +namespace media_manager { + +CREATE_LOGGERPTR_GLOBAL(logger_, "FromMicRecorderListener") + +FromMicRecorderListener::FromMicRecorderListener( + const std::string& file_name) + : reader_(NULL) + , file_name_(file_name) { +} + +FromMicRecorderListener::~FromMicRecorderListener() { + if (reader_) { + reader_->stop(); + delete reader_; + reader_ = NULL; + } +} + +void FromMicRecorderListener::OnDataReceived( + int32_t application_key, + const DataForListener& data) { +} + +void FromMicRecorderListener::OnErrorReceived( + int32_t application_key, + const DataForListener& data) { +} + +void FromMicRecorderListener::OnActivityStarted(int32_t application_key) { + LOG4CXX_INFO(logger_, "FromMicRecorderListener::OnActivityStarted " + << application_key); + if (application_key == current_application_) { + return; + } + if (!reader_) { + AudioStreamSenderThread* thread_delegate = + new AudioStreamSenderThread(file_name_, application_key); + reader_ = new threads::Thread("RecorderSender", thread_delegate); + } + if (reader_) { + reader_->start(); + current_application_ = application_key; + } +} + +void FromMicRecorderListener::OnActivityEnded(int32_t application_key) { + LOG4CXX_INFO(logger_, "FromMicRecorderListener::OnActivityEnded " + << application_key); + if (application_key != current_application_) { + LOG4CXX_WARN(logger_, "Not performing activity on " << application_key + << " but on " << current_application_); + return; + } + if (reader_) { + reader_->stop(); + delete reader_; + reader_ = NULL; + } + current_application_ = 0; +} + +} // namespace media_manager diff --git a/src/components/media_manager/src/audio/from_mic_to_file_recorder_thread.cc b/src/components/media_manager/src/audio/from_mic_to_file_recorder_thread.cc new file mode 100644 index 0000000000..02ccd1f2b7 --- /dev/null +++ b/src/components/media_manager/src/audio/from_mic_to_file_recorder_thread.cc @@ -0,0 +1,266 @@ +/* +* Copyright (c) 2014, Ford Motor Company +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the +* distribution. +* +* Neither the name of the Ford Motor Company nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "media_manager/audio/from_mic_to_file_recorder_thread.h" +#include <unistd.h> +#include <sstream> +#include "utils/logger.h" + +namespace media_manager { + +CREATE_LOGGERPTR_GLOBAL(logger_, "FromMicToFileRecorderThread") + +GMainLoop* FromMicToFileRecorderThread::loop = NULL; + +FromMicToFileRecorderThread::FromMicToFileRecorderThread( + const std::string& output_file, int32_t duration) + : threads::ThreadDelegate(), + argc_(5), + oKey_("-o"), + tKey_("-t"), + sleepThread_(NULL), + outputFileName_(output_file) { + LOG4CXX_TRACE_ENTER(logger_); + set_record_duration(duration); +} + +void FromMicToFileRecorderThread::set_output_file( + const std::string& output_file) { + LOG4CXX_TRACE_ENTER(logger_); + + outputFileName_ = output_file; +} + +void FromMicToFileRecorderThread::set_record_duration(int32_t duration) { + LOG4CXX_TRACE_ENTER(logger_); + + std::stringstream stringStream; + stringStream << duration / 1000; + durationString_ = stringStream.str(); +} + +void FromMicToFileRecorderThread::initArgs() { + LOG4CXX_TRACE_ENTER(logger_); + + argv_ = new gchar*[argc_]; + + argv_[0] = new gchar[14]; + argv_[1] = new gchar[3]; + argv_[2] = new gchar[outputFileName_.length() + 1]; + argv_[3] = new gchar[3]; + argv_[4] = new gchar[durationString_.length() + 1]; + + argv_[0] = const_cast<gchar*>(std::string("AudioManager").c_str()); + argv_[1] = const_cast<gchar*>(oKey_.c_str()); + argv_[2] = const_cast<gchar*>(outputFileName_.c_str()); + argv_[3] = const_cast<gchar*>(tKey_.c_str()); + argv_[4] = const_cast<gchar*>(durationString_.c_str()); +} + +void FromMicToFileRecorderThread::threadMain() { + LOG4CXX_TRACE_ENTER(logger_); + + { + sync_primitives::AutoLock auto_lock(stopFlagLock_); + shouldBeStoped_ = false; + } + + initArgs(); + + GstElement* pipeline; + GstElement* alsasrc, *wavenc, *filesink; + GstBus* bus; + + const gchar* device = "hw:0,0"; + gchar* outfile = NULL; + gint duration = -1; + GOptionContext* context = NULL; + GError* err = NULL; + GOptionEntry entries[] = { { + "device", 'd', 0, G_OPTION_ARG_FILENAME, &device, + "device file (Default: hw:0,0)", "SRC" + }, { + "output", 'o', 0, G_OPTION_ARG_FILENAME, &outfile, + "save output of the stream to DEST", "DEST" + }, { + "duration", 't', 0, G_OPTION_ARG_INT, &duration, + "length of time in seconds to capture", "int32_t" + }, { + NULL + } + }; +#ifndef GLIB_VERSION_2_32 // g_thread_init() does nothing since 2.32 + if (!g_thread_supported()) { + g_thread_init(NULL); + } +#endif + // Parse the arguments + context = g_option_context_new("-- M-AUDIO RAW"); + g_option_context_add_main_entries(context, entries, NULL); + g_option_context_add_group(context, gst_init_get_option_group()); + if (!g_option_context_parse(context, &argc_, &argv_, &err)) { + g_error("%s\n", err->message); + } + + // Check for proper arguments + if (outfile == NULL) { + g_error("Must supply destination (-d FILE)\n"); + } + + LOG4CXX_TRACE(logger_, "Reading from device: " << device); + LOG4CXX_TRACE(logger_, "Saving pipeline output to: " << outfile); + LOG4CXX_TRACE(logger_, "Duration set to: " << duration); + + // Initialize gstreamer and setup the main loop information + gst_init(&argc_, &argv_); + + pipeline = gst_pipeline_new("vga2usb-h264"); + + // Set up error handling + bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); + gst_bus_add_watch(bus, + reinterpret_cast<int32_t (*)(_GstBus*, _GstMessage*, void*)> + (recvmsg), + NULL); + gst_object_unref(bus); + + // Create all of the elements to be added to the pipeline + alsasrc = gst_element_factory_make("alsasrc", "alsasrc0"); + wavenc = gst_element_factory_make("wavenc", "wavenc0"); + filesink = gst_element_factory_make("filesink", "filesink0"); + + // Assert that all the elements were created + if (!alsasrc || !wavenc || !filesink) { + g_error("Failed creating one or more of the pipeline elements.\n"); + } + + // Set input and output destinations + g_object_set(G_OBJECT(alsasrc), "device", device, NULL); + g_object_set(G_OBJECT(filesink), "location", outfile, NULL); + + // Add the elements to the pipeline + gst_bin_add_many(GST_BIN(pipeline), alsasrc, wavenc, filesink, NULL); + + // Link the elements + gst_element_link_many(alsasrc, wavenc, filesink, NULL); + + gst_element_set_state(pipeline, GST_STATE_PLAYING); + + LOG4CXX_TRACE(logger_, "Initializing pipeline ..."); + while (GST_STATE(pipeline) != GST_STATE_PLAYING) { + LOG4CXX_TRACE(logger_, "GST_STATE(pipeline) != GST_STATE_PLAYING"); + + bool shouldBeStoped; + { + sync_primitives::AutoLock auto_lock(stopFlagLock_); + shouldBeStoped = shouldBeStoped_; + } + + if (shouldBeStoped) { + return; + } + } + + LOG4CXX_TRACE(logger_, "Pipeline started ...\n"); + + // Start up a timer for the pipeline + if (duration > 0) { + GstTimeout timeout; + timeout.pipeline = pipeline; + timeout.duration = duration; + + sleepThread_ = new threads::Thread("SleepThread" + , new SleepThreadDelegate(timeout)); + + if (NULL != sleepThread_) { + sleepThread_->start(); + } + } + + loop = g_main_loop_new(NULL, FALSE); + + g_main_loop_run(loop); + + gst_element_set_state(pipeline, GST_STATE_NULL); + + LOG4CXX_TRACE(logger_, "Deleting pipeline\n"); + gst_object_unref(GST_OBJECT(pipeline)); + g_main_loop_unref(loop); + + loop = NULL; +} + +FromMicToFileRecorderThread::SleepThreadDelegate::SleepThreadDelegate(GstTimeout + timeout) + : threads::ThreadDelegate(), + timeout_(timeout) { +} + +void FromMicToFileRecorderThread::SleepThreadDelegate::threadMain() { + LOG4CXX_TRACE(logger_, "Sleep for " << timeout_.duration << " seconds"); + + sleep(timeout_.duration); + + if (NULL != loop) { + if (g_main_loop_is_running(loop)) { + gst_element_send_event(timeout_.pipeline, gst_event_new_eos()); + } + } +} + +bool FromMicToFileRecorderThread::exitThreadMain() { + LOG4CXX_TRACE_ENTER(logger_); + + if (NULL != loop) { + if (g_main_loop_is_running(loop)) { + LOG4CXX_TRACE(logger_, "Quit loop\n"); + g_main_loop_quit(loop); + } + } + + if (NULL != sleepThread_) { + LOG4CXX_TRACE(logger_, "Stop sleep thread\n"); + sleepThread_->stop(); + delete sleepThread_; + sleepThread_ = NULL; + } + + LOG4CXX_TRACE(logger_, "Set should be stopped flag\n"); + { + sync_primitives::AutoLock auto_lock(stopFlagLock_); + shouldBeStoped_ = true; + } + + return true; +} + +} // namespace media_manager diff --git a/src/components/media_manager/src/audio/pipe_audio_streamer_adapter.cc b/src/components/media_manager/src/audio/pipe_audio_streamer_adapter.cc new file mode 100644 index 0000000000..5faebf93d5 --- /dev/null +++ b/src/components/media_manager/src/audio/pipe_audio_streamer_adapter.cc @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "media_manager/audio/pipe_audio_streamer_adapter.h" +#include "config_profile/profile.h" +#include "utils/logger.h" + +namespace media_manager { + +CREATE_LOGGERPTR_GLOBAL(logger, "PipeAudioStreamerAdapter") + +PipeAudioStreamerAdapter::PipeAudioStreamerAdapter() { + LOG4CXX_INFO(logger, "PipeAudioStreamerAdapter::PipeAudioStreamerAdapter"); + named_pipe_path_ = profile::Profile::instance()->named_audio_pipe_path(); + + Init(); +} + +PipeAudioStreamerAdapter::~PipeAudioStreamerAdapter() { + LOG4CXX_INFO(logger, "PipeAudioStreamerAdapter::~PipeAudioStreamerAdapter"); +} + +} // namespace media_manager diff --git a/src/components/media_manager/src/audio/socket_audio_streamer_adapter.cc b/src/components/media_manager/src/audio/socket_audio_streamer_adapter.cc new file mode 100644 index 0000000000..eb93032e42 --- /dev/null +++ b/src/components/media_manager/src/audio/socket_audio_streamer_adapter.cc @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config_profile/profile.h" +#include "media_manager/audio/socket_audio_streamer_adapter.h" +#include "utils/logger.h" + +namespace media_manager { + +CREATE_LOGGERPTR_GLOBAL(logger, "SocketAudioStreamerAdapter") + +SocketAudioStreamerAdapter::SocketAudioStreamerAdapter() { + LOG4CXX_INFO(logger, "SocketAudioStreamerAdapter::SocketAudioStreamerAdapter"); + port_ = profile::Profile::instance()->audio_streaming_port(); + ip_ = profile::Profile::instance()->server_address(); + + Init(); +} + +SocketAudioStreamerAdapter::~SocketAudioStreamerAdapter() { +} +} // namespace media_manager |