Progress commit on message file transfer:

- upload and download works,
- download only works for runtime messages. Messages pulled from DB will make belle-sip crash
- can't cancel the transfer for the moment (waiting for API to fix that)
This commit is contained in:
Guillaume BIENKOWSKI 2014-07-10 14:27:48 +02:00
parent 831a7f222f
commit 7467caa879
4 changed files with 136 additions and 128 deletions

View file

@ -23,7 +23,7 @@
@protocol ChatRoomDelegate <NSObject>
- (BOOL)chatRoomStartImageDownload:(NSURL*)url userInfo:(id)userInfo;
- (BOOL)chatRoomStartImageDownload:(LinphoneChatMessage*)msg;
- (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url;
- (void)resendChat:(NSString*)message withExternalUrl:(NSString*)url;

View file

@ -29,7 +29,7 @@
#include "linphone/linphonecore.h"
@interface ChatRoomViewController : UIViewController<HPGrowingTextViewDelegate, UICompositeViewDelegate, ImagePickerDelegate, ImageSharingDelegate, ChatRoomDelegate, LinphoneChatContentTransferDelegate> {
@interface ChatRoomViewController : UIViewController<HPGrowingTextViewDelegate, UICompositeViewDelegate, ImagePickerDelegate, ChatRoomDelegate, LinphoneChatContentTransferDelegate> {
LinphoneChatRoom *chatRoom;
ImageSharing *imageSharing;
OrderedDictionary *imageQualities;

View file

@ -21,6 +21,7 @@
#import "PhoneMainView.h"
#import "DTActionSheet.h"
#import "UILinphone.h"
#import "UIAlertView+Blocks.h"
#import <NinePatch.h>
#import <MobileCoreServices/UTCoreTypes.h>
@ -28,9 +29,10 @@
@implementation ChatRoomViewController {
/* Message transfer transient storage */
/* TODO: use this for data retrieval */
NSData* image;
size_t offset_sent;
NSData* upload_data;
size_t upload_bytes_sent;
NSMutableData* download_data;
}
@synthesize tableController;
@ -68,8 +70,9 @@
[NSNumber numberWithFloat:0.0], NSLocalizedString(@"Minimum", nil), nil];
self->composingVisible = TRUE;
self->image = nil;
self->offset_sent = 0;
self->upload_data = nil;
self->upload_bytes_sent = 0;
self->download_data = nil;
}
return self;
}
@ -199,8 +202,8 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if(imageSharing) {
[imageSharing cancel];
if(upload_data || download_data ) {
// TODO: when the API permits it, we should cancel the transfer.
}
[messageField resignFirstResponder];
@ -269,7 +272,7 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)update {
if(chatRoom == NULL) {
[LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot update chat room header: null contact"];
Linphone_warn(@"Cannot update chat room header: null contact");
return;
}
@ -314,18 +317,17 @@ static UICompositeViewDescription *compositeDescription = nil;
static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) {
ChatRoomViewController* thiz = (ChatRoomViewController*)ud;
const char*text = linphone_chat_message_get_text(msg);
[LinphoneLogger log:LinphoneLoggerLog
format:@"Delivery status for [%s] is [%s]",text,linphone_chat_message_state_to_string(state)];
Linphone_log(@"Delivery status for [%s] is [%s]",text,linphone_chat_message_state_to_string(state));
[thiz.tableController updateChatEntry:msg];
}
- (BOOL)sendMessage:(NSString *)message withExterlBodyUrl:(NSURL*)externalUrl withInternalURL:(NSURL*)internalUrl {
if(![LinphoneManager isLcReady]) {
[LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot send message: Linphone core not ready"];
Linphone_warn(@"Cannot send message: Linphone core not ready");
return FALSE;
}
if(chatRoom == NULL) {
[LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot send message: No chatroom"];
Linphone_warn(@"Cannot send message: No chatroom");
return FALSE;
}
@ -347,35 +349,7 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
}
- (void)saveAndSend:(UIImage*)image url:(NSURL*)url {
if(url == nil) {
[waitView setHidden:FALSE];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[LinphoneManager instance].photoLibrary
writeImageToSavedPhotosAlbum:image.CGImage
orientation:(ALAssetOrientation)[image imageOrientation]
completionBlock:^(NSURL *assetURL, NSError *error){
dispatch_async(dispatch_get_main_queue(), ^{
[waitView setHidden:TRUE];
if (error) {
[LinphoneLogger log:LinphoneLoggerError format:@"Cannot save image data downloaded [%@]", [error localizedDescription]];
UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil)
message:NSLocalizedString(@"Cannot write image to photo library", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Ok",nil)
otherButtonTitles:nil ,nil];
[errorAlert show];
[errorAlert release];
return;
}
[LinphoneLogger log:LinphoneLoggerLog format:@"Image saved to [%@]", [assetURL absoluteString]];
[self chatRoomStartImageUpload:image url:assetURL];
});
}];
});
} else {
[self chatRoomStartImageUpload:image url:url];
}
[self chatRoomStartImageUpload:image url:url];
}
- (void)chooseImageQuality:(UIImage*)image url:(NSURL*)url {
@ -536,8 +510,19 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
#pragma mark - Action Functions
- (IBAction)onBackClick:(id)event {
[self.tableController setChatRoom:NULL];
[[PhoneMainView instance] popCurrentView];
if( upload_data != nil || download_data != nil ){
[UIAlertView showWithTitle:NSLocalizedString(@"Cancel transfer?", nil)
message:NSLocalizedString(@"You have a transfer in progress, leaving this view will cancel it. Are you sure?", nil)
cancelButtonTitle:NSLocalizedString(@"Cancel", nil)
otherButtonTitles:@[NSLocalizedString(@"Yes", nil)]
tapBlock:^(UIAlertView *alertView, NSInteger buttonIndex) {
if( buttonIndex == 1 ){
[self.tableController setChatRoom:NULL];
[[PhoneMainView instance] popCurrentView];
}
}];
}
}
- (IBAction)onEditClick:(id)event {
@ -621,9 +606,18 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
#pragma mark ChatRoomDelegate
- (BOOL)chatRoomStartImageDownload:(NSURL*)url userInfo:(id)userInfo {
if(imageSharing == nil) {
imageSharing = [ImageSharing newImageSharingDownload:url delegate:self userInfo:userInfo];
- (BOOL)chatRoomStartImageDownload:(LinphoneChatMessage*)msg {
if(self->download_data == nil) {
const char* url = linphone_chat_message_get_external_body_url(msg);
Linphone_log(@"Content to download: %s", url);
if( url == nil ) return FALSE;
download_data = [[NSMutableData alloc] init];
linphone_chat_message_set_user_data(msg, self);
linphone_chat_message_start_file_download(msg);
[messageView setHidden:TRUE];
[transferView setHidden:FALSE];
return TRUE;
@ -632,14 +626,13 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
}
- (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url{
if(imageSharing == nil) {
NSData* jpegData = UIImageJPEGRepresentation(image, 1.0);
if( self->upload_data == nil) {
LinphoneContent content = {};
content.type = "image";
content.subtype = "jpeg";
content.name = ms_strdup([[NSString stringWithFormat:@"%i-%f.jpg", [image hash],[NSDate timeIntervalSinceReferenceDate]] UTF8String]);
content.data = (void*)[jpegData bytes];
content.size = [jpegData length];
self->upload_data = [UIImageJPEGRepresentation(image, 1.0) retain];
content.type = "image";
content.subtype = "jpeg";
content.name = ms_strdup([[NSString stringWithFormat:@"%i-%f.jpg", [image hash],[NSDate timeIntervalSinceReferenceDate]] UTF8String]);
content.size = [self->upload_data length];
LinphoneChatMessage* message = linphone_chat_room_create_file_transfer_message(chatRoom, &content);
linphone_chat_message_set_user_data(message, self);
@ -649,8 +642,14 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
[LinphoneManager setValueInMessageAppData:[url absoluteString] forKey:@"localimage" inMessage:message];
}
// TODO: in the user data, we should maybe put a standalone delegate alloced and retained, instead of self.
// This will make sure that when receiving a memory alert or go to another view, we still send the message
linphone_chat_room_send_message2(chatRoom, message, message_status, self);
if( content.name ){
ms_free(content.name);
}
[tableController addChatEntry:linphone_chat_message_ref(message)];
[tableController scrollToBottom:true];
[messageView setHidden:TRUE];
@ -666,10 +665,6 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
#pragma mark ImageSharingDelegate
- (void)imageSharingProgress:(ImageSharing*)aimageSharing progress:(float)progress {
[imageTransferProgressBar setProgress:progress];
}
- (void)imageSharingAborted:(ImageSharing*)aimageSharing {
[messageView setHidden:FALSE];
[transferView setHidden:TRUE];
@ -677,68 +672,6 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
imageSharing = nil;
}
- (void)imageSharingError:(ImageSharing*)aimageSharing error:(NSError *)error {
[messageView setHidden:FALSE];
[transferView setHidden:TRUE];
NSString *url = [aimageSharing.connection.currentRequest.URL absoluteString];
if (aimageSharing.upload) {
[LinphoneLogger log:LinphoneLoggerError format:@"Cannot upload file to server [%@] because [%@]", url, [error localizedDescription]];
UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil)
message:NSLocalizedString(@"Cannot transfer file to remote contact", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Ok",nil)
otherButtonTitles:nil ,nil];
[errorAlert show];
[errorAlert release];
} else {
[LinphoneLogger log:LinphoneLoggerError format:@"Cannot download file from [%@] because [%@]", url, [error localizedDescription]];
UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil)
message:NSLocalizedString(@"Cannot transfer file from remote contact", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Continue", nil)
otherButtonTitles:nil, nil];
[errorAlert show];
[errorAlert release];
}
imageSharing = nil;
}
- (void)imageSharingUploadDone:(ImageSharing*)aimageSharing url:(NSURL*)url{
[self sendMessage:nil withExterlBodyUrl:url withInternalURL:[aimageSharing userInfo] ];
[messageView setHidden:FALSE];
[transferView setHidden:TRUE];
imageSharing = nil;
}
- (void)imageSharingDownloadDone:(ImageSharing*)aimageSharing image:(UIImage *)image {
[messageView setHidden:FALSE];
[transferView setHidden:TRUE];
__block LinphoneChatMessage *chat = (LinphoneChatMessage *)[(NSValue*)[imageSharing userInfo] pointerValue];
[[LinphoneManager instance].photoLibrary writeImageToSavedPhotosAlbum:image.CGImage
orientation:(ALAssetOrientation)[image imageOrientation]
completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
[LinphoneLogger log:LinphoneLoggerError format:@"Cannot save image data downloaded [%@]", [error localizedDescription]];
UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil)
message:NSLocalizedString(@"Cannot write image to photo library", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Ok",nil)
otherButtonTitles:nil ,nil];
[errorAlert show];
[errorAlert release];
return;
}
[LinphoneLogger log:LinphoneLoggerLog format:@"Image saved to [%@]", [assetURL absoluteString]];
[LinphoneManager setValueInMessageAppData:[assetURL absoluteString] forKey:@"localimage" inMessage:chat];
[tableController updateChatEntry:chat];
}];
imageSharing = nil;
}
#pragma mark ImagePickerDelegate
- (void)imagePickerDelegateImage:(UIImage*)image info:(NSDictionary *)info {
@ -758,15 +691,92 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
#pragma mark - LinphoneChatContentTransferDelegate
- (void)onProgressReport:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content percent:(int)percent {
[imageTransferProgressBar setProgress:percent];
[imageTransferProgressBar setProgress:percent/100.0f];
}
- (void)onDataRequested:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(char *)buffer withSize:(size_t *)size {
// TODO
if( self->upload_data ){
size_t to_send = *size;
size_t remaining = [upload_data length] - self->upload_bytes_sent;
Linphone_log(@"Asking %ld bytes, sent %ld of %d, %ld remaining", to_send, self->upload_bytes_sent, [upload_data length], remaining);
if( remaining < to_send ) to_send = remaining;
@try {
[upload_data getBytes:(void*)buffer range:NSMakeRange(upload_bytes_sent, to_send)];
upload_bytes_sent += to_send;
*size = to_send;
}
@catch (NSException *exception) {
Linphone_err(@"Exception: %@", exception);
}
if( to_send == 0 || upload_bytes_sent == [upload_data length] ){
Linphone_log(@"Upload finished, cleanup..");
[upload_data release];
upload_data = nil;
upload_bytes_sent = 0;
// update UI
dispatch_async(dispatch_get_main_queue(), ^{
[messageView setHidden:FALSE];
[transferView setHidden:TRUE];
});
}
} else {
Linphone_err(@"Error: no upload data in progress!");
}
}
- (void)onDataReceived:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(const char *)buffer withSize:(size_t)size {
// TODO
if( download_data ){
Linphone_log(@"Receiving data for %s : %zu bytes, already got %d of %zu",content->name, size, [download_data length], content->size);
if( size != 0 ){
[download_data appendBytes:buffer length:size];
}
if( size == 0 && [download_data length] == content->size ){
Linphone_log(@"Transfer is finished, save image and update chat");
dispatch_async(dispatch_get_main_queue(), ^{
//we're finished, save the image and update the message
[messageView setHidden:FALSE];
[transferView setHidden:TRUE];
UIImage* image = [UIImage imageWithData:download_data];
[download_data release];
download_data = nil;
[[LinphoneManager instance].photoLibrary
writeImageToSavedPhotosAlbum:image.CGImage
orientation:(ALAssetOrientation)[image imageOrientation]
completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
Linphone_err(@"Cannot save image data downloaded [%@]", [error localizedDescription]);
UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil)
message:NSLocalizedString(@"Cannot write image to photo library", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Ok",nil)
otherButtonTitles:nil ,nil];
[errorAlert show];
[errorAlert release];
return;
}
Linphone_log(@"Image saved to [%@]", [assetURL absoluteString]);
[LinphoneManager setValueInMessageAppData:[assetURL absoluteString] forKey:@"localimage" inMessage:msg];
[tableController updateChatEntry:msg];
}];
});
}
}
}
#pragma mark - Keyboard Event Functions
@ -781,7 +791,7 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
[UIView setAnimationCurve:curve];
[UIView setAnimationBeginsFromCurrentState:TRUE];
CGFloat composeIndicatorCompensation = composingVisible ? composeIndicatorView.frame.size.height : 0.0f;
// Resize chat view
{
CGRect chatFrame = [[self chatView] frame];

View file

@ -315,9 +315,7 @@ static UIFont *CELL_FONT = nil;
}
- (IBAction)onDownloadClick:(id)event {
NSURL* url = [NSURL URLWithString:[NSString stringWithUTF8String:linphone_chat_message_get_external_body_url(chat)]];
[chatRoomDelegate chatRoomStartImageDownload:url userInfo:[NSValue valueWithPointer:chat]];
[chatRoomDelegate chatRoomStartImageDownload:chat];
}
- (IBAction)onImageClick:(id)event {