michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set sw=2 ts=8 et tw=80 : */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "RtspControllerParent.h" michael@0: #include "RtspController.h" michael@0: #include "nsIAuthPromptProvider.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsProxyRelease.h" michael@0: #include "mozilla/ipc/InputStreamUtils.h" michael@0: #include "mozilla/ipc/URIUtils.h" michael@0: #include "mozilla/unused.h" michael@0: #include "nsNetUtil.h" michael@0: #include "prlog.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: PRLogModuleInfo* gRtspLog; michael@0: #undef LOG michael@0: #define LOG(args) PR_LOG(gRtspLog, PR_LOG_DEBUG, args) michael@0: michael@0: #define SEND_DISCONNECT_IF_ERROR(rv) \ michael@0: if (NS_FAILED(rv) && mIPCOpen && mTotalTracks > 0ul) { \ michael@0: for (uint32_t i = 0; i < mTotalTracks; i++) { \ michael@0: unused << SendOnDisconnected(i, rv); \ michael@0: } \ michael@0: } michael@0: michael@0: using namespace mozilla::ipc; michael@0: michael@0: namespace mozilla { michael@0: namespace net { michael@0: michael@0: void michael@0: RtspControllerParent::Destroy() michael@0: { michael@0: // If we're being destroyed on a non-main thread, we AddRef again and use a michael@0: // proxy to release the RtspControllerParent on the main thread, where the michael@0: // RtspControllerParent is deleted. This ensures we only delete the michael@0: // RtspControllerParent on the main thread. michael@0: if (!NS_IsMainThread()) { michael@0: nsCOMPtr mainThread = do_GetMainThread(); michael@0: NS_ENSURE_TRUE_VOID(mainThread); michael@0: nsRefPtr doomed(this); michael@0: if (NS_FAILED(NS_ProxyRelease(mainThread, michael@0: static_cast(doomed), true))) { michael@0: NS_WARNING("Failed to proxy release to main thread!"); michael@0: } michael@0: } else { michael@0: delete this; michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_ADDREF(RtspControllerParent) michael@0: NS_IMPL_RELEASE_WITH_DESTROY(RtspControllerParent, Destroy()) michael@0: NS_IMPL_QUERY_INTERFACE(RtspControllerParent, michael@0: nsIInterfaceRequestor, michael@0: nsIStreamingProtocolListener) michael@0: michael@0: RtspControllerParent::RtspControllerParent() michael@0: : mIPCOpen(true) michael@0: , mTotalTracks(0) michael@0: { michael@0: #if defined(PR_LOGGING) michael@0: if (!gRtspLog) michael@0: gRtspLog = PR_NewLogModule("nsRtsp"); michael@0: #endif michael@0: } michael@0: michael@0: RtspControllerParent::~RtspControllerParent() michael@0: { michael@0: } michael@0: michael@0: void michael@0: RtspControllerParent::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: LOG(("RtspControllerParent::ActorDestroy()")); michael@0: mIPCOpen = false; michael@0: michael@0: NS_ENSURE_TRUE_VOID(mController); michael@0: if (mController) { michael@0: mController->Stop(); michael@0: mController = nullptr; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: RtspControllerParent::RecvAsyncOpen(const URIParams& aURI) michael@0: { michael@0: LOG(("RtspControllerParent::RecvAsyncOpen()")); michael@0: michael@0: mURI = DeserializeURI(aURI); michael@0: michael@0: mController = new RtspController(nullptr); michael@0: mController->Init(mURI); michael@0: nsresult rv = mController->AsyncOpen(this); michael@0: if (NS_SUCCEEDED(rv)) return true; michael@0: michael@0: mController = nullptr; michael@0: return SendAsyncOpenFailed(rv); michael@0: } michael@0: michael@0: bool michael@0: RtspControllerParent::RecvPlay() michael@0: { michael@0: LOG(("RtspControllerParent::RecvPlay()")); michael@0: NS_ENSURE_TRUE(mController, true); michael@0: michael@0: nsresult rv = mController->Play(); michael@0: SEND_DISCONNECT_IF_ERROR(rv) michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: RtspControllerParent::RecvPause() michael@0: { michael@0: LOG(("RtspControllerParent::RecvPause()")); michael@0: NS_ENSURE_TRUE(mController, true); michael@0: michael@0: nsresult rv = mController->Pause(); michael@0: SEND_DISCONNECT_IF_ERROR(rv) michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: RtspControllerParent::RecvResume() michael@0: { michael@0: LOG(("RtspControllerParent::RecvResume()")); michael@0: NS_ENSURE_TRUE(mController, true); michael@0: michael@0: nsresult rv = mController->Resume(); michael@0: SEND_DISCONNECT_IF_ERROR(rv) michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: RtspControllerParent::RecvSuspend() michael@0: { michael@0: LOG(("RtspControllerParent::RecvSuspend()")); michael@0: NS_ENSURE_TRUE(mController, true); michael@0: michael@0: nsresult rv = mController->Suspend(); michael@0: SEND_DISCONNECT_IF_ERROR(rv) michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: RtspControllerParent::RecvSeek(const uint64_t& offset) michael@0: { michael@0: LOG(("RtspControllerParent::RecvSeek()")); michael@0: NS_ENSURE_TRUE(mController, true); michael@0: michael@0: nsresult rv = mController->Seek(offset); michael@0: SEND_DISCONNECT_IF_ERROR(rv) michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: RtspControllerParent::RecvStop() michael@0: { michael@0: LOG(("RtspControllerParent::RecvStop()")); michael@0: NS_ENSURE_TRUE(mController, true); michael@0: michael@0: nsresult rv = mController->Stop(); michael@0: NS_ENSURE_SUCCESS(rv, true); michael@0: return true; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RtspControllerParent::OnMediaDataAvailable(uint8_t index, michael@0: const nsACString & data, michael@0: uint32_t length, michael@0: uint32_t offset, michael@0: nsIStreamingProtocolMetaData *meta) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(meta); michael@0: uint32_t int32Value; michael@0: uint64_t int64Value; michael@0: michael@0: nsresult rv = meta->GetTimeStamp(&int64Value); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: michael@0: LOG(("RtspControllerParent:: OnMediaDataAvailable %d:%d time %lld", michael@0: index, length, int64Value)); michael@0: michael@0: // Serialize meta data. michael@0: nsCString name; michael@0: name.AssignLiteral("TIMESTAMP"); michael@0: InfallibleTArray metaData; michael@0: metaData.AppendElement(RtspMetadataParam(name, int64Value)); michael@0: michael@0: name.AssignLiteral("FRAMETYPE"); michael@0: rv = meta->GetFrameType(&int32Value); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: metaData.AppendElement(RtspMetadataParam(name, int32Value)); michael@0: michael@0: nsCString stream; michael@0: stream.Assign(data); michael@0: if (!mIPCOpen || michael@0: !SendOnMediaDataAvailable(index, stream, length, offset, metaData)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RtspControllerParent::OnConnected(uint8_t index, michael@0: nsIStreamingProtocolMetaData *meta) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(meta); michael@0: uint32_t int32Value; michael@0: uint64_t int64Value; michael@0: michael@0: LOG(("RtspControllerParent:: OnConnected")); michael@0: // Serialize meta data. michael@0: InfallibleTArray metaData; michael@0: nsCString name; michael@0: name.AssignLiteral("TRACKS"); michael@0: nsresult rv = meta->GetTotalTracks(&mTotalTracks); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: metaData.AppendElement(RtspMetadataParam(name, mTotalTracks)); michael@0: michael@0: name.AssignLiteral("MIMETYPE"); michael@0: nsCString mimeType; michael@0: rv = meta->GetMimeType(mimeType); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: metaData.AppendElement(RtspMetadataParam(name, mimeType)); michael@0: michael@0: name.AssignLiteral("WIDTH"); michael@0: rv = meta->GetWidth(&int32Value); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: metaData.AppendElement(RtspMetadataParam(name, int32Value)); michael@0: michael@0: name.AssignLiteral("HEIGHT"); michael@0: rv = meta->GetHeight(&int32Value); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: metaData.AppendElement(RtspMetadataParam(name, int32Value)); michael@0: michael@0: name.AssignLiteral("DURATION"); michael@0: rv = meta->GetDuration(&int64Value); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: metaData.AppendElement(RtspMetadataParam(name, int64Value)); michael@0: michael@0: name.AssignLiteral("SAMPLERATE"); michael@0: rv = meta->GetSampleRate(&int32Value); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: metaData.AppendElement(RtspMetadataParam(name, int32Value)); michael@0: michael@0: name.AssignLiteral("TIMESTAMP"); michael@0: rv = meta->GetTimeStamp(&int64Value); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: metaData.AppendElement(RtspMetadataParam(name, int64Value)); michael@0: michael@0: name.AssignLiteral("CHANNELCOUNT"); michael@0: rv = meta->GetChannelCount(&int32Value); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: metaData.AppendElement(RtspMetadataParam(name, int32Value)); michael@0: michael@0: nsCString esds; michael@0: rv = meta->GetEsdsData(esds); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: name.AssignLiteral("ESDS"); michael@0: metaData.AppendElement(RtspMetadataParam(name, esds)); michael@0: michael@0: nsCString avcc; michael@0: rv = meta->GetAvccData(avcc); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: name.AssignLiteral("AVCC"); michael@0: metaData.AppendElement(RtspMetadataParam(name, avcc)); michael@0: michael@0: if (!mIPCOpen || !SendOnConnected(index, metaData)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RtspControllerParent::OnDisconnected(uint8_t index, michael@0: nsresult reason) michael@0: { michael@0: LOG(("RtspControllerParent::OnDisconnected() for track %d reason = 0x%x", index, reason)); michael@0: if (!mIPCOpen || !SendOnDisconnected(index, reason)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: if (mController) { michael@0: mController = nullptr; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RtspControllerParent::GetInterface(const nsIID & iid, void **result) michael@0: { michael@0: LOG(("RtspControllerParent::GetInterface()")); michael@0: return QueryInterface(iid, result); michael@0: } michael@0: michael@0: } // namespace net michael@0: } // namespace mozilla