Commit 0eb233d5 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk

video: hardware decoding/encoding

Change-Id: Ia86d0a42802438cc9eaba15b768eee4f4a01a941
parent caf0e652
......@@ -139,6 +139,10 @@
0E7CF4DD20165BFB00CD967D /* ButtonsContainerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7CF4DC20165BFB00CD967D /* ButtonsContainerViewModel.swift */; };
0E7CF4DF2017918300CD967D /* ButtonsContainerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E7CF4DE2017918300CD967D /* ButtonsContainerView.xib */; };
0E8E9A0520483E1200DA8E8B /* TitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8E9A0420483E1200DA8E8B /* TitleView.swift */; };
0E96ED72225CFDB50016C07D /* encoder.json in Resources */ = {isa = PBXBuildFile; fileRef = 0E96ED71225CFDB50016C07D /* encoder.json */; };
0E96ED75225D06250016C07D /* GeneralSettingsViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E96ED74225D06250016C07D /* GeneralSettingsViewController.storyboard */; };
0E96ED77225D06380016C07D /* GeneralSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E96ED76225D06380016C07D /* GeneralSettingsViewController.swift */; };
0E96ED79225D06480016C07D /* GeneralSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E96ED78225D06480016C07D /* GeneralSettingsViewModel.swift */; };
0E983E6E1FC77C3E0082103E /* ConversationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E983E6D1FC77C3E0082103E /* ConversationModel.swift */; };
0E99F1A022417A0400CF8BD6 /* JamiURI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E99F19F22417A0400CF8BD6 /* JamiURI.swift */; };
0E9D84491FA7DA6A00C561EB /* ChatTabBarItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D84481FA7DA6A00C561EB /* ChatTabBarItemViewModel.swift */; };
......@@ -150,6 +154,7 @@
0EB479951FA28A7300106AFD /* ButtonTransparentBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB479941FA28A7300106AFD /* ButtonTransparentBackground.swift */; };
0EBB72A92034F44200D88F46 /* ProfilesService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBB72A82034F44200D88F46 /* ProfilesService.swift */; };
0EBCAA4E202E60F000E2A545 /* default.wav in Resources */ = {isa = PBXBuildFile; fileRef = 0EBCAA4D202E60F000E2A545 /* default.wav */; };
0ECEE9A3220D1935000E1CF4 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0ECEE9A2220D1935000E1CF4 /* VideoToolbox.framework */; };
0ED2B6FA1F96A075001572F0 /* LinkNewDeviceViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0ED2B6F91F96A075001572F0 /* LinkNewDeviceViewController.storyboard */; };
0ED2B6FC1F96A158001572F0 /* LinkNewDeviceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED2B6FB1F96A158001572F0 /* LinkNewDeviceViewController.swift */; };
0ED2B6FE1F96A16C001572F0 /* LinkNewDeviceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED2B6FD1F96A16C001572F0 /* LinkNewDeviceViewModel.swift */; };
......@@ -462,6 +467,10 @@
0E7CF4DC20165BFB00CD967D /* ButtonsContainerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonsContainerViewModel.swift; sourceTree = "<group>"; };
0E7CF4DE2017918300CD967D /* ButtonsContainerView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ButtonsContainerView.xib; sourceTree = "<group>"; };
0E8E9A0420483E1200DA8E8B /* TitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleView.swift; sourceTree = "<group>"; };
0E96ED71225CFDB50016C07D /* encoder.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = encoder.json; sourceTree = "<group>"; };
0E96ED74225D06250016C07D /* GeneralSettingsViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = GeneralSettingsViewController.storyboard; sourceTree = "<group>"; };
0E96ED76225D06380016C07D /* GeneralSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsViewController.swift; sourceTree = "<group>"; };
0E96ED78225D06480016C07D /* GeneralSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsViewModel.swift; sourceTree = "<group>"; };
0E983E6D1FC77C3E0082103E /* ConversationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationModel.swift; sourceTree = "<group>"; };
0E99F19F22417A0400CF8BD6 /* JamiURI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JamiURI.swift; sourceTree = "<group>"; };
0E9D84481FA7DA6A00C561EB /* ChatTabBarItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatTabBarItemViewModel.swift; sourceTree = "<group>"; };
......@@ -474,6 +483,7 @@
0EB479941FA28A7300106AFD /* ButtonTransparentBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonTransparentBackground.swift; sourceTree = "<group>"; };
0EBB72A82034F44200D88F46 /* ProfilesService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilesService.swift; sourceTree = "<group>"; };
0EBCAA4D202E60F000E2A545 /* default.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = default.wav; sourceTree = "<group>"; };
0ECEE9A2220D1935000E1CF4 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
0ED2B6F91F96A075001572F0 /* LinkNewDeviceViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LinkNewDeviceViewController.storyboard; sourceTree = "<group>"; };
0ED2B6FB1F96A158001572F0 /* LinkNewDeviceViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkNewDeviceViewController.swift; sourceTree = "<group>"; };
0ED2B6FD1F96A16C001572F0 /* LinkNewDeviceViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkNewDeviceViewModel.swift; sourceTree = "<group>"; };
......@@ -688,6 +698,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0ECEE9A3220D1935000E1CF4 /* VideoToolbox.framework in Frameworks */,
628F4DCF206C0AEE0009C44C /* libcrypto.a in Frameworks */,
628F4DCD206BF4740009C44C /* libtls.a in Frameworks */,
628F4DCB206BE23B0009C44C /* libssl.a in Frameworks */,
......@@ -796,6 +807,7 @@
children = (
0E639459224AB32200C0890A /* Contacts.framework */,
0EB12451224AB1030025F8CA /* ContactsUI.framework */,
0ECEE9A2220D1935000E1CF4 /* VideoToolbox.framework */,
628F4DCE206C0AEE0009C44C /* libcrypto.a */,
628F4DCC206BF4730009C44C /* libtls.a */,
628F4DCA206BE23B0009C44C /* libssl.a */,
......@@ -1200,6 +1212,16 @@
path = CreateSipAccount;
sourceTree = "<group>";
};
0E96ED73225D05F70016C07D /* GeneralSettings */ = {
isa = PBXGroup;
children = (
0E96ED74225D06250016C07D /* GeneralSettingsViewController.storyboard */,
0E96ED76225D06380016C07D /* GeneralSettingsViewController.swift */,
0E96ED78225D06480016C07D /* GeneralSettingsViewModel.swift */,
);
path = GeneralSettings;
sourceTree = "<group>";
};
0E9D84471FA7D9EC00C561EB /* TabBar */ = {
isa = PBXGroup;
children = (
......@@ -1241,6 +1263,7 @@
1A0C4EBC1F1D48AA00550433 /* Features */ = {
isa = PBXGroup;
children = (
0E96ED73225D05F70016C07D /* GeneralSettings */,
0E320D4E224ADF570070B515 /* Dialpad */,
6613A610214AF8B100B497D1 /* QRCode */,
0E3BD4222044770000A50DDF /* Contact */,
......@@ -1489,6 +1512,7 @@
1ABE07C61F0D86B300D36361 /* Resources */ = {
isa = PBXGroup;
children = (
0E96ED71225CFDB50016C07D /* encoder.json */,
0EBCAA4D202E60F000E2A545 /* default.wav */,
1ABE07DA1F0D915100D36361 /* Localizable.strings */,
04399A021D1C2D9D00E99CD9 /* Images.xcassets */,
......@@ -1749,6 +1773,7 @@
0E6F545622403ADE00ECC3CE /* CreateSipAccountViewController.storyboard in Resources */,
1A2D18FD1F292DAD00B2C785 /* ConversationCell.xib in Resources */,
0E320D50224ADF840070B515 /* DialpadViewController.storyboard in Resources */,
0E96ED72225CFDB50016C07D /* encoder.json in Resources */,
1ABE07DC1F0D915100D36361 /* Localizable.strings in Resources */,
0EBCAA4E202E60F000E2A545 /* default.wav in Resources */,
1A2D18E61F29197100B2C785 /* MessageAccessoryView.xib in Resources */,
......@@ -1780,6 +1805,7 @@
5CE66F751FBF769B00EE9291 /* InitialLoadingViewController.storyboard in Resources */,
1A5DC03E1F35678D0075E8EF /* ContactRequestsViewController.storyboard in Resources */,
0E72374A20460320006B0C7D /* ProfileHeaderView.xib in Resources */,
0E96ED75225D06250016C07D /* GeneralSettingsViewController.storyboard in Resources */,
0EB1A5CF1F8EBE03009923E2 /* DeviceCell.xib in Resources */,
1A2D18B31F2915C500B2C785 /* ConversationViewController.storyboard in Resources */,
0E7CF4DF2017918300CD967D /* ButtonsContainerView.xib in Resources */,
......@@ -1942,6 +1968,7 @@
1A20418D1F1EABCC00C08435 /* StateableResponsive.swift in Sources */,
1A0C4EE51F1D67DF00550433 /* WalkthroughCoordinator.swift in Sources */,
1A2D18DD1F29192D00B2C785 /* MessableBubble.swift in Sources */,
0E96ED77225D06380016C07D /* GeneralSettingsViewController.swift in Sources */,
0E99F1A022417A0400CF8BD6 /* JamiURI.swift in Sources */,
1A5DC02E1F3565640075E8EF /* ConversationViewModel.swift in Sources */,
0EBB72A92034F44200D88F46 /* ProfilesService.swift in Sources */,
......@@ -2036,6 +2063,7 @@
0EF78DE31FD0AE3000FC6966 /* ConversationsManager.swift in Sources */,
0EAA9DB42029F0AA005E245C /* ProxyCell.swift in Sources */,
66266FC021557D2F002757A6 /* ScanViewModel.swift in Sources */,
0E96ED79225D06480016C07D /* GeneralSettingsViewModel.swift in Sources */,
1A2041801F1E903B00C08435 /* CreateProfileViewController.swift in Sources */,
66266FC4215C18F8002757A6 /* Emoji+Helpers.swift in Sources */,
0E0FF1B71FC398B3003898C2 /* ConversationDataHepler.swift in Sources */,
......@@ -2289,7 +2317,10 @@
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Ring/RingPrefixHeader.pch;
HEADER_SEARCH_PATHS = "$(SRCROOT)/../fat/include";
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../fat/include",
"$(SRCROOT)/../../daemon/contrib/native-arm64/ffmpeg",
);
INFOPLIST_FILE = Ring/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
......@@ -2326,7 +2357,10 @@
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Ring/RingPrefixHeader.pch;
HEADER_SEARCH_PATHS = "$(SRCROOT)/../fat/include";
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../fat/include",
"$(SRCROOT)/../../daemon/contrib/native-arm64/ffmpeg",
);
INFOPLIST_FILE = Ring/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
......@@ -2488,7 +2522,10 @@
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Ring/RingPrefixHeader.pch;
HEADER_SEARCH_PATHS = "$(SRCROOT)/../fat/include";
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../fat/include",
"$(SRCROOT)/../../daemon/contrib/native-arm64/ffmpeg",
);
INFOPLIST_FILE = Ring/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
......
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "62366028200914C1002598C1"
BuildableName = "libring"
BlueprintName = "libring"
ReferencedContainer = "container:Ring.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "62366028200914C1002598C1"
BuildableName = "libring"
BlueprintName = "libring"
ReferencedContainer = "container:Ring.xcodeproj">
</BuildableReference>
</MacroExpansion>
<EnvironmentVariables>
<EnvironmentVariable
key = "AVLOGLEVEL"
value = "40"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "62366028200914C1002598C1"
BuildableName = "libring"
BlueprintName = "libring"
ReferencedContainer = "container:Ring.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
......@@ -117,8 +117,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
// sets output device to whatever is currently available (either spk / headset)
self.audioService.startAVAudioSession()
// disables hardware decoding
self.videoService.setDecodingAccelerated(withState: false)
prepareVideoAcceleration()
// requests permission to use the camera
// will enumerate and add devices once permission has been granted
......@@ -161,6 +160,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
}
guard let currentAccount = self.accountService.currentAccount else {
self.log.error("Can't get current account!")
//if we don't have any account means it is first run, so enable hardware acceleration
self.videoService.setDecodingAccelerated(withState: true)
self.videoService.setEncodingAccelerated(withState: true)
UserDefaults.standard.set(true, forKey: hardareAccelerationKey)
return
}
self.reloadDataFor(account: currentAccount)
......@@ -219,6 +222,29 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
self.clearBadgeNumber()
}
func prepareVideoAcceleration() {
// we want enable hardware acceleration by default so if key does not exists,
// means it was not disabled by user
let keyExists = UserDefaults.standard.object(forKey: hardareAccelerationKey) != nil
let enable = keyExists ? UserDefaults.standard.bool(forKey: hardareAccelerationKey) : false
self.videoService.setDecodingAccelerated(withState: enable)
self.videoService.setEncodingAccelerated(withState: enable)
guard let codecInfoPath = Bundle.main.path(forResource: "encoder",
ofType: ".json") else {return}
guard let destPath =
NSSearchPathForDirectoriesInDomains(.documentDirectory,
.userDomainMask,
true).first else {return}
let fileManager = FileManager.default
guard let fullDestPath = NSURL(fileURLWithPath: destPath)
.appendingPathComponent("encoder.json") else {return}
let fullDestPathString = fullDestPath.path
do {
try fileManager.copyItem(atPath: codecInfoPath,
toPath: fullDestPathString)
} catch { }
}
// MARK: - Ring Daemon
fileprivate func startDaemon() {
......
......@@ -24,6 +24,7 @@
#import <map>
#import <string>
#import <vector>
struct AVFrame;
@interface Utils : NSObject
......@@ -35,4 +36,6 @@
+ (NSData*)dataFromVectorOfUInt8:(std::vector<uint8_t>)vectorOfUInt8;
+ (std::vector<uint8_t>)vectorOfUInt8FromData:(NSData*)data;
+ (std::vector<std::map<std::string, std::string>>)arrayOfDictionnarisToVectorOfMap:(NSArray*)dictionaries;
+ (UIImage*)convertHardwareDecodedFrameToImage:(const AVFrame*)frame;
+ (AVFrame*)configureHardwareDecodedFrame:(AVFrame*)frame fromImageBuffer: (CVImageBufferRef) image;
@end
......@@ -20,6 +20,9 @@
*/
#import "Utils.h"
extern "C" {
#include <libavutil/frame.h>
}
@implementation Utils
......@@ -105,4 +108,26 @@
return vector;
}
+ (UIImage*)convertHardwareDecodedFrameToImage:(const AVFrame*)frame {
if ((CVPixelBufferRef)frame->data[3]) {
CIImage *image = [CIImage imageWithCVPixelBuffer: (CVPixelBufferRef)frame->data[3]];
UIImage * imageUI = [UIImage imageWithCIImage:image];
return imageUI;
}
return [[UIImage alloc] init];
}
+ (AVFrame*)configureHardwareDecodedFrame:(AVFrame*)frame fromImageBuffer:(CVImageBufferRef) image {
//get dimensions
CVPixelBufferLockBaseAddress(image,0);
size_t width = CVPixelBufferGetWidth(image);
size_t height = CVPixelBufferGetHeight(image);
CVPixelBufferUnlockBaseAddress(image,0);
frame->data[3] = (uint8_t *)image;
frame->format = AV_PIX_FMT_VIDEOTOOLBOX;
frame->width = static_cast<int>(width);
frame->height = static_cast<int>(height);
return frame;
}
@end
......@@ -20,6 +20,7 @@
#import <Foundation/Foundation.h>
#import <AVFoundation/AVCaptureOutput.h>
#import <AVFoundation/AVFoundation.h>
@protocol VideoAdapterDelegate;
......@@ -30,9 +31,13 @@
- (void)addVideoDeviceWithName:(NSString*)deviceName withDevInfo:(NSDictionary*)deviceInfoDict;
- (void)registerSinkTargetWithSinkId:sinkId withWidth:(NSInteger)w withHeight:(NSInteger)h;
- (void)removeSinkTargetWithSinkId:(NSString*)sinkId;
- (void)writeOutgoingHardwareDecodedFrameWithBuffer:(CVImageBufferRef)image;
- (void)writeOutgoingFrameWithImage:(UIImage*)image;
- (void)setDecodingAccelerated:(BOOL)state;
- (BOOL)getDecodingAccelerated;
- (void)switchInput:(NSString*)deviceName;
- (void)switchInput:(NSString*)deviceName forCall:(NSString*) callID;
- (void)setEncodingAccelerated:(BOOL)state;
- (BOOL)getEncodingAccelerated;
@end
......@@ -27,6 +27,7 @@
#include <functional>
#include <AVFoundation/AVFoundation.h>
#include <mutex>
#import "Utils.h"
using namespace DRing;
......@@ -36,11 +37,26 @@ struct Renderer
std::condition_variable frameCv;
bool isRendering;
std::mutex renderMutex;
AVSinkTarget avtarget;
SinkTarget target;
SinkTarget::FrameBufferPtr daemonFramePtr_;
int width;
int height;
void bindAVSinkFunctions() {
avtarget.push = [this](std::unique_ptr<DRing::VideoFrame> frame) {
if(!VideoAdapter.delegate) {
return;
}
@autoreleasepool {
UIImage *image = [Utils
convertHardwareDecodedFrameToImage: std::move(frame->pointer())];
isRendering = true;
[VideoAdapter.delegate writeFrameWithImage: image];
isRendering = false;
}
};
}
void bindSinkFunctions() {
target.pull = [this](std::size_t bytes) {
std::lock_guard<std::mutex> lk(renderMutex);
......@@ -146,8 +162,13 @@ static id <VideoAdapterDelegate> _delegate;
auto renderer = std::make_shared<Renderer>();
renderer->width = static_cast<int>(w);
renderer->height = static_cast<int>(h);
renderer->bindSinkFunctions();
DRing::registerSinkTarget(_sinkId, renderer->target);
if(self.getDecodingAccelerated) {
renderer->bindAVSinkFunctions();
DRing::registerAVSinkTarget(_sinkId, renderer->avtarget);
} else {
renderer->bindSinkFunctions();
DRing::registerSinkTarget(_sinkId, renderer->target);
}
renderers.insert(std::make_pair(_sinkId, renderer));
}
......@@ -162,7 +183,17 @@ static id <VideoAdapterDelegate> _delegate;
}
}
- (void)writeOutgoingFrameWithImage:(UIImage*)image {
- (void)writeOutgoingHardwareDecodedFrameWithBuffer:(CVImageBufferRef)image {
auto frame = DRing::getNewFrame();
if(!frame) {
return;
}
auto avframe = frame->pointer();
[Utils configureHardwareDecodedFrame:(AVFrame*)avframe fromImageBuffer: image];
DRing::publishFrame();
}
- (void)writeOutgoingFrameWithImage:(UIImage *)image {
unsigned capacity = 4 * image.size.width * image.size.height;
uint8_t* buf = (uint8_t*)DRing::obtainFrame(capacity);
if (buf){
......@@ -196,6 +227,18 @@ static id <VideoAdapterDelegate> _delegate;
DRing::setDecodingAccelerated(state);
}
- (BOOL)getDecodingAccelerated {
return DRing::getDecodingAccelerated();
}
- (void)setEncodingAccelerated:(BOOL)state {
DRing::setEncodingAccelerated(state);
}
- (BOOL)getEncodingAccelerated {
return DRing::getEncodingAccelerated();
}
- (void)switchInput:(NSString*)deviceName {
DRing::switchInput(std::string([deviceName UTF8String]));
}
......
......@@ -57,6 +57,7 @@ internal enum Asset {
internal static let ringLogo = ImageAsset(name: "ring_logo")
internal static let scan = ImageAsset(name: "scan")
internal static let sendButton = ImageAsset(name: "send_button")
internal static let settings = ImageAsset(name: "settings")
internal static let settingsIcon = ImageAsset(name: "settings_icon")
internal static let shareButton = ImageAsset(name: "share_button")
internal static let stopCall = ImageAsset(name: "stop_call")
......
......@@ -291,6 +291,13 @@ internal enum L10n {
internal static let readableStatusSuccess = L10n.tr("Localizable", "dataTransfer.readableStatusSuccess")
}
internal enum GeneralSettings {
/// General settings
internal static let title = L10n.tr("Localizable", "generalSettings.title")
/// Enable video acceleration
internal static let videoAcceleration = L10n.tr("Localizable", "generalSettings.videoAcceleration")
}
internal enum GeneratedMessage {
/// Contact added
internal static let contactAdded = L10n.tr("Localizable", "generatedMessage.contactAdded")
......
......@@ -41,7 +41,7 @@ class ContactViewModel: ViewModel, Stateable {
private let accountService: AccountsService
private let conversationService: ConversationsService
private let nameService: NameService
lazy var tableSection : Observable<[SectionModel<String, ContactActions>]> = {
lazy var tableSection: Observable<[SectionModel<String, ContactActions>]> = {
let jamiSettings =
[SectionModel(model: "ProfileInfoCell",
items:
......
......@@ -57,6 +57,8 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, ConversationNa
self.createNewAccount()
case .showDialpad(let inCall):
self.showDialpad(inCall: inCall)
case .showGeneralSettings:
self.showGeneralSettings()
default:
break
}
......@@ -109,6 +111,11 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, ConversationNa
}
}
func showGeneralSettings() {
let settingsViewController = GeneralSettingsViewController.instantiate(with: self.injectionBag)
self.present(viewController: settingsViewController, withStyle: .present, withAnimation: true, disposeBag: self.disposeBag)
}
func puchConversation(participantId: String) {
let conversationViewModel = ConversationViewModel(with: self.injectionBag)
guard let account = accountService.currentAccount else {
......
......@@ -72,21 +72,56 @@
<constraint firstItem="HKv-H1-GYI" firstAttribute="centerX" secondItem="e5o-cY-djH" secondAttribute="centerX" priority="750" id="yI5-9z-dUv"/>
</constraints>
</view>
<searchBar contentMode="redraw" placeholder="Enter name..." translatesAutoresizingMaskIntoConstraints="NO" id="xPr-nI-I35">
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="DKd-eF-L6f">
<rect key="frame" x="0.0" y="20" width="375" height="56"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="tintColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<offsetWrapper key="searchFieldBackgroundPositionAdjustment" horizontal="0.0" vertical="0.0"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" returnKeyType="done"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
<real key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" red="0.92156862745098034" green="0.92156862745098034" blue="0.92156862745098034" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</searchBar>
<subviews>
<searchBar contentMode="redraw" placeholder="Enter name..." translatesAutoresizingMaskIntoConstraints="NO" id="xPr-nI-I35">
<rect key="frame" x="0.0" y="0.0" width="325" height="56"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="56" id="4yw-AN-guZ"/>
</constraints>
<color key="tintColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<offsetWrapper key="searchFieldBackgroundPositionAdjustment" horizontal="0.0" vertical="0.0"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" returnKeyType="done"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
<real key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" red="0.92156862745098034" green="0.92156862745098034" blue="0.92156862745098034" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</searchBar>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RSG-bY-flb">
<rect key="frame" x="325" y="8" width="40" height="40"/>
<color key="tintColor" red="0.2470588235" green="0.42745098040000001" blue="0.65490196079999996" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" image="phone_book"/>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Eta-uf-Ija">
<rect key="frame" x="325" y="8" width="40" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="eb8-7R-X3e"/>
<constraint firstAttribute="height" constant="40" id="j8h-fg-qMp"/>
</constraints>
<color key="tintColor" red="0.2470588235" green="0.42745098040000001" blue="0.65490196079999996" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" image="qr_code_scan"/>
</button>
</subviews>
<color key="backgroundColor" red="0.92549019607843142" green="0.92549019607843142" blue="0.92549019607843142" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="Eta-uf-Ija" firstAttribute="top" secondItem="RSG-bY-flb" secondAttribute="top" id="C2I-Kv-faQ"/>
<constraint firstItem="Eta-uf-Ija" firstAttribute="centerY" secondItem="xPr-nI-I35" secondAttribute="centerY" id="Epv-9a-Rkg"/>
<constraint firstAttribute="trailing" secondItem="Eta-uf-Ija" secondAttribute="trailing" constant="10" id="O7M-He-7UH"/>
<constraint firstItem="Eta-uf-Ija" firstAttribute="leading" secondItem="xPr-nI-I35" secondAttribute="trailing" id="SnW-M7-wRB"/>
<constraint firstItem="Eta-uf-Ija" firstAttribute="trailing" secondItem="RSG-bY-flb" secondAttribute="trailing" id="fK5-6j-fKX"/>
<constraint firstItem="Eta-uf-Ija" firstAttribute="leading" secondItem="RSG-bY-flb" secondAttribute="leading" id="ggB-jL-tbn"/>
<constraint firstItem="xPr-nI-I35" firstAttribute="leading" secondItem="DKd-eF-L6f" secondAttribute="leading" id="m1O-ZV-Pkx"/>
<constraint firstItem="xPr-nI-I35" firstAttribute="top" secondItem="DKd-eF-L6f" secondAttribute="top" id="nlW-pc-ggm"/>
<constraint firstItem="Eta-uf-Ija" firstAttribute="bottom" secondItem="RSG-bY-flb" secondAttribute="bottom" id="wOa-Ne-n5e"/>
<constraint firstAttribute="bottom" secondItem="xPr-nI-I35" secondAttribute="bottom" id="xcp-FC-G0l"/>
</constraints>
</view>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="HFM-G6-hMN">
<rect key="frame" x="0.0" y="132" width="375" height="535"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
......@@ -165,21 +200,21 @@
<constraints>
<constraint firstItem="opE-y7-3Rm" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="0cn-0y-g9L"/>
<constraint firstItem="EvL-Bu-O1T" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="2Cw-xT-xCg"/>
<constraint firstItem="xPr-nI-I35" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="4NO-53-KBh"/>
<constraint firstAttribute="trailing" secondItem="HFM-G6-hMN" secondAttribute="trailing" id="7H1-ka-2Ti"/>
<constraint firstItem="cfq-zl-uux" firstAttribute="top" secondItem="79Q-fh-vhV" secondAttribute="bottom" constant="30" id="8G6-0D-3ma"/>
<constraint firstItem="HFM-G6-hMN" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="8tr-Rd-1kr"/>
<constraint firstItem="e5o-cY-djH" firstAttribute="top" secondItem="xPr-nI-I35" secondAttribute="bottom" id="CLm-6J-lYv"/>
<constraint firstItem="DKd-eF-L6f" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="9fi-2r-wE8"/>
<constraint firstAttribute="trailing" secondItem="DKd-eF-L6f" secondAttribute="trailing" id="AhH-s9-pfe"/>
<constraint firstAttribute="trailing" secondItem="opE-y7-3Rm" secondAttribute="trailing" id="D0f-nM-KEs"/>
<constraint firstItem="HFM-G6-hMN" firstAttribute="top" secondItem="e5o-cY-djH" secondAttribute="bottom" id="KK7-rp-AZz"/>
<constraint firstItem="opE-y7-3Rm" firstAttribute="top" secondItem="e5o-cY-djH" secondAttribute="bottom" id="NKz-A0-hLf"/>
<constraint firstItem="xPr-nI-I35" firstAttribute="top" secondItem="sbJ-yn-t3e" secondAttribute="bottom" id="OX7-et-d3F"/>
<constraint firstItem="cfq-zl-uux" firstAttribute="top" secondItem="EvL-Bu-O1T" secondAttribute="bottom" id="TsM-9H-eI1"/>
<constraint firstItem="cfq-zl-uux" firstAttribute="top" secondItem="HFM-G6-hMN" secondAttribute="bottom" id="VfB-5H-uHq"/>
<constraint firstItem="EvL-Bu-O1T" firstAttribute="top" secondItem="e5o-cY-djH" secondAttribute="bottom" id="aH0-7e-i4a"/>
<constraint firstAttribute="trailing" secondItem="xPr-nI-I35" secondAttribute="trailing" id="dtX-d4-r9P"/>
<constraint firstAttribute="trailing" secondItem="79Q-fh-vhV" secondAttribute="trailing" constant="30" id="elh-uT-3vG"/>
<constraint firstItem="DKd-eF-L6f" firstAttribute="top" secondItem="sbJ-yn-t3e" secondAttribute="bottom" id="gbl-PR-kL4"/>
<constraint firstAttribute="trailing" secondItem="e5o-cY-djH" secondAttribute="trailing" id="k9v-18-oxL"/>
<constraint firstItem="e5o-cY-djH" firstAttribute="top" secondItem="xPr-nI-I35" secondAttribute="bottom" id="mKv-lK-yDx"/>
<constraint firstAttribute="trailing" secondItem="EvL-Bu-O1T" secondAttribute="trailing" id="nSK-QH-snj"/>
<constraint firstItem="e5o-cY-djH" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="rXu-fF-ESz"/>
<constraint firstItem="cfq-zl-uux" firstAttribute="top" secondItem="opE-y7-3Rm" secondAttribute="bottom" id="wun-hC-1JP"/>
......@@ -193,10 +228,14 @@
<outlet property="dialpadButton" destination="k8G-Me-4BI" id="Ij7-SF-nvZ"/>
<outlet property="dialpadButtonShadow" destination="79Q-fh-vhV" id="VcA-wc-j6h"/>
<outlet property="networkAlertLabel" destination="Fu7-Dr-XvA" id="0qV-lk-9mE"/>
<outlet property="networkAlertViewTopConstraint" destination="CLm-6J-lYv" id="LEO-Ep-Gpx"/>
<outlet property="networkAlertViewTopConstraint" destination="mKv-lK-yDx" id="bJk-Ie-hf6"/>
<outlet property="noConversationLabel" destination="8bB-XU-6gh" id="n4g-mz-w7z"/>
<outlet property="noConversationsView" destination="EvL-Bu-O1T" id="tVV-6a-4Xg"/>
<outlet property="phoneBookButton" destination="RSG-bY-flb" id="Yjw-Va-7c1"/>
<outlet property="qrScanButton" destination="Eta-uf-Ija" id="Hh0-vy-8EK"/>
<outlet property="scanButtonLeadingConstraint" destination="O7M-He-7UH" id="cvF-Wd-TJT"/>
<outlet property="searchBar" destination="xPr-nI-I35" id="Y3U-rV-yfc"/>
<outlet property="searchBarShadow" destination="DKd-eF-L6f" id="CKZ-ws-ag1"/>
<outlet property="searchResultsTableView" destination="opE-y7-3Rm" id="F3g-9d-IQt"/>
<outlet property="searchTableViewLabel" destination="4Yu-Fe-ixq" id="dq3-QM-bfA"/>
<outlet property="settingsButton" destination="iaz-fd-fEz" id="R2O-R8-BDk"/>
......@@ -210,6 +249,8 @@
</scenes>
<resources>
<image name="dialpad" width="75" height="75"/>
<image name="phone_book" width="75" height="75"/>
<image name="qr_code_scan" width="48" height="48"/>
<image name="settings_icon" width="48" height="48"/>
</resources>
</document>
......@@ -55,6 +55,10 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
@IBOutlet weak var settingsButton: UIButton!
@IBOutlet weak var dialpadButton: UIButton!
@IBOutlet weak var dialpadButtonShadow: UIView!
@IBOutlet weak var searchBarShadow: UIView!
@IBOutlet weak var qrScanButton: UIButton!
@IBOutlet weak var phoneBookButton: UIButton!
@IBOutlet weak var scanButtonLeadingConstraint: NSLayoutConstraint!
// account selection
var accounPicker = UIPickerView()
......@@ -151,21 +155,22 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
}
}).disposed(by: self.disposeBag)
let imageScanSearch = UIImage(asset: Asset.qrCodeScan) as UIImage?
let scanButton = UIButton(type: UIButtonType.custom) as UIButton
scanButton.setImage(imageScanSearch, for: .normal)
let scanButtonItem = UIBarButtonItem(customView: scanButton)
scanButton.rx.tap.throttle(0.5, scheduler: MainScheduler.instance)
let imageSettings = UIImage(asset: Asset.settings) as UIImage?
let generalSettingsButton = UIButton(type: UIButtonType.system) as UIButton
generalSettingsButton.setImage(imageSettings, for: .normal)
generalSettingsButton.contentMode = .scaleAspectFill
let settingsButtonItem = UIBarButtonItem(customView: generalSettingsButton)
generalSettingsButton.rx.tap.throttle(0.5, scheduler: MainScheduler.instance)
.subscribe(onNext: { [unowned self] in
self.viewModel.showGeneralSettings()
})
.disposed(by: self.disposeBag)
qrScanButton.rx.tap.throttle(0.5, scheduler: MainScheduler.instance)
.subscribe(onNext: { [unowned self] in
self.openScan()
})
.disposed(by: self.disposeBag)
let imageOpenPhoneContacts = UIImage(asset: Asset.phoneBook) as UIImage?
let phoneBookButton = UIButton(type: UIButtonType.custom) as UIButton
phoneBookButton.setImage(imageOpenPhoneContacts, for: .normal)
phoneBookButton.contentMode = .scaleAspectFill
let contactsButtonItem = UIBarButtonItem(customView: phoneBookButton)
phoneBookButton.rx.tap.throttle(0.5, scheduler: MainScheduler.instance)
.subscribe(onNext: { [unowned self] in
self.contactPicker.delegate = self
......@@ -178,15 +183,23 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
if let account = currentAccount {
let accountSip = account.type == AccountType.sip
self.navigationItem
.rightBarButtonItem = accountSip ? contactsButtonItem : scanButtonItem
.rightBarButtonItem = accountSip ? nil : settingsButtonItem