개발/미디어개발

[iOS] AudioQueueInputCallback buffer 오디오 데이터 자르기

hagulu 하구루2017.02.25 16:45

AudioToolbox 에 AudioQueue 를 사용해서 레코딩을 하게 되는데,

AudioQueueInputCallback 를 통해서 인코딩된 음성 데이터를 얻어 올 수 있다.

이를 통해서 얻어온 오디오 데이터는 하나의 패킷이 아니라 여러 패킷이 하나로 뭉쳐있는 형태이다. 파일로 저장 할떄는 AudioFile.h 내의 메소드를 사용하면 큰 무리 없이 파일 저장이 가능하다.

하지만 데이터를 스트림 서버로 전달해야 하는 경우에는 달랐다.
일단 콜백을 통해서 전달되는 경우에는 데이터에 ADTS 데이터가 포함되어 있지 않다.
그 부분은 아래 포스팅 한 방식으로 어렵지 않게 추가가 가능하다.

하지만, 문제는 전달되는 데이터가 여러 패킷의 연속된 데이터라, 각 패킷마다 ADTS정보를
넣어 주어야 하는데 각 패킷의 자를 방법을 찾아야 했다.
콜백으로 전달된 데이터 중에 분명 해당 정보가 있을것이라 생각하고 파본 결과 역시나 존재하고 있었다.
void (*AudioQueueInputCallback)(
                 void *                  inUserData,
                 AudioQueueRef           inAQ,
                 AudioQueueBufferRef     inBuffer,
                 const AudioTimeStamp *  inStartTime,
                 UInt32                  inNumberPacketDescriptions,
                 const AudioStreamPacketDescription *inPacketDescs);
콜백의 원형은 위와 같다.
위 파라미터에서 inPacketDescs 이녀석을 주목하면 된다.

AudioStreamPacketDescription 구조체 타입이고 원형은 아래와 같다.
struct  AudioStreamPacketDescription
{
    SInt64  mStartOffset;
    UInt32  mVariableFramesInPacket;
    UInt32  mDataByteSize;
};
typedef struct AudioStreamPacketDescription AudioStreamPacketDescription;
보는것처럼 패킷의 offset과 size 정보가 들어 있다.
이를 통해서 packet을 나누어 주면 된다.
그리고 패킷은 inNumberPacketDescriptions개 이다.
inPacketDescs 은 보는것처럼 포인터로 배열 처럼 데이터가 저장되어 있다.

 inNumberPacketDescriptions 만큼 루프를 돌면서 inPacketDescs[1] 의 형태로 접근하면,
각각 패킷의 offset과 size정보를 얻어 올수 있게 된다.

이를 이용해서 각 패킷앞에 ADTS 데이터를 붙여주면 스트림으로 전달 가능한 완전한 오디오 데이터가 완성이 될수 있다.


신고

댓글

댓글쓰기 폼

개발/미디어개발

[미디어] ACC ADTS 생성하기

hagulu 하구루2017.02.25 16:44

AAC 는 최근 가장 많이 쓰이는 음성 코덱중에 하나이다.

아이폰과 아이팟에서 적극적으로 사용하면서 많이 확산된 코덱이다.
그와 관련 된 내용은 위키를 참조하기 바란다.

AAC 는 압축된 음성 데이터이고 이에 대응하는 헤더 정보가 ADTS이다.
ADTS를 들여다 보면 현재 압축되어 있는 음성정보에 대한 정보를 알수 있고,
디코더는 이 정보를 통해서 압축을 해제하여 PCM 데이터를 추출하게 된다.
그런데 가끔 AAC 를 다루다보면 압축된 데이터만 있고,  ADTS를 따로 추가해 줘야 하는 경우가 생긴다.

이런 상황에서 직접 ADTS를 생성하는 방법을 소개하려 한다.
일단 ADTS에 대한 정확한 정보는 아래 링크를 통해서 확인할수 있다.
링크를 보면 알수 있지만 총 7byte로 이루어 져있다.
(CRC를 포함한 9byte 형태도 있다.)

영어로 되어있고 복잡해 보이지만 여기서 주목해야할 데이터는 총 4가지이다.
2. Samplerate
3. Channels
4. 데이터 크기

1. MPEG-4 Audio Object Type 은 흔히 말하는 Audio Profile 이다.
아래 링크에 프로파일 인덱스가 있고 이 인덱스에서 1을 빼준값을 사용한다.
(*프로파일을 모를 때는 AAC LC (Low Complexity) 로 해보기 바란다. 최근에 가장 많이 쓰이는 프로파일이다) 

2. Samplerate도 인덱스로 입력이 되는데 해당 인덱스는 아래 링크를 확인하면 된다.

3. Channels 는 오디오의 채널을 그대로 입력하면 된다.
4. 데이터 크기는 헤더 크기 까지 포함한 전체 데이터 크기이다.

요 4가지만 입력해주면 헤더 정보는 완성된다.
다른부분은 적당한 기본값으로 채워 주면 된다.

아래와 같이 해당 변수에 적당한 값을 넣어주면 ADTS 데이터가 완성된다.

        Byte packet[7];
        // fill in ADTS data
        packet[0] = (Byte)0xFF;
        packet[1] = (Byte)0xF9;
        packet[2] = (Byte)(((audioProfile-1)<<6) + (sampleIndex<<2) +(channels>>2));
        packet[3] = (Byte)(((channels&0x3)<<6) + (dataLength>>11));
        packet[4] = (Byte)((dataLength&0x7FF) >> 3);
        packet[5] = (Byte)(((dataLength&0x7)<<5) + 0x1F);
        packet[6] = (Byte)0xFC;


이렇게 완성된 7byte를 AAC 데이터 앞에 붙여 주면 완성된다.


신고

댓글

댓글쓰기 폼

개발/기타

[Git] git-svn을 이용하여 subversion git로 옮기기

hagulu 하구루2017.02.25 16:43

기존 subversion 사용자들 중에 git로 옮기려는 수요가 꽤 많은 것으로 알고 있다.


git를 svn과 비교했을때 가장 큰 장점은 로컬에서도 마음껏 버젼 관리를 할 수 있고,
branch 관리가 subversion에 비해서 월등히 이용이 쉽다.

그리고 Mac사용자들은 subversion GUI툴이 딱히 쏙 맘에 드는 것이 없을 것이다.
git는 source Tree라는 강력한 툴을 무려! 무료로 사용 할수 있다.

하지만 옮기기에는 몇가지 걸림돌이 있다.

일단, git와 subversion은 비슷한듯 다른 면이 많이 있기 때문에,
새로 익히고 공부 해야 한다.
버젼관리 툴의 특성상 사용의 실수로 엄청난 재앙을 몰고 올수도 있기 때문에 익숙하게 사용하지 못하면 큰 위험이 따른다.
이점은 어떤 친절한 능력자 님께서 올려 주신 슬라이드를 보면 조금 쉽게 이해할 수 있을 것이다.
아래 링크를 참조 하기 바란다.



두번째로 subversion에서  지금까지 유지해오던 history의 유지이다.
버젼관리에서 기존 history는 굉장히 많은 의미를 가지기 때문에, 이를 유지 해서 옮겨야 할 것이다.
이 부분은 감사한 git가 모두 처리해 준다.

git-svn이라는 기능을 이용하는 것인데 git에 내장 되어 있다.

사용법은 매우~ 간단하다.

git svn clone {Repository address}

터미널 에서 간단하게 해당 명령을 이용하면 svn에 있는 history와 함께 git를 tree를 구성해 준다. (git가 설치 되고 셋팅되어 있어야한다)
clone이 무엇인지 모른다면 git에 대해 좀더 파악후 진행해보기 바란다.

추가로, 기존 branches나 tags를 포함해서 history를 유지하게 할수 있다.

git svn clone -T {trunk directory name} -b {branches directory name} -t {tags directory name} {Repository address}

위와 같이 trunk, branches, tags의 디렉토리 경로를 Repository 주소로 부터 상대 경로로 위와 같이 해주면 모든 history를 유지한 git tree를 clone할 수 있다.

실행해보면 알겠지만 정말 깔끔하게 정리되어 있는 것을 볼수 있다.

 위 방법으로 clone을 하게 되면 git와 subversion 동시에 적용이 가능하도록 할 수도 있다. 하지만 테스트 결과 그렇게 깔끔하게 subversion에 commit이 되지 안아서 추천하고 싶지는 않은 기능이다.  


신고

'개발 > 기타' 카테고리의 다른 글

[Git] git-svn을 이용하여 subversion git로 옮기기  (0) 2017.02.25

댓글

댓글쓰기 폼

2013 이전/기타

[UNIX] cat 리다이렉션 주의 사항

hagulu 하구루2017.02.25 16:43

간단한 파일 입출력을 위해서 cat을 이용하는 경우가 종종 있을 것이다. 간단한 명령어기 때문에 별 생각 없이 써왔던 명령어였는데, 실수를 통해서 좀 깊이 알게되어 정리 해보려 한다.


 내가 했던 실수는 다음과 같다.
 
 test1.txt 와 test2.txt의 내용을  test3.txt에 저장하려고 하였다.
그런데 실수로 아래와 같이 해버렸다.

$cat test* > test3.txt

위 문장은 풀어서 쓰면 다음과 같다

$cat test1.txt test2.txt test3.txt > test3.txt

 위처럼 자기 자신 까지 포함해서 test3.txt에 저장이 되게 한 것이다. 그래도 test3.txt가 내용이 존재 하지 않기때문에 별 문제없을 것이라고 생각했다. 그런데, 신기하게도 무한 루프가 걸리면서 test1과 test2의 내용이 반복해서 test3.txt에 저장되고 있었다. 무슨일이 일어난 것일까?
 대충 생각하면, 자기자신에게 저장이 되다보니 그럴수도 있을것 같은데, 명확한 이유를 알고 싶었다. 직접 cat명령어의 소스도 찾아서 분석하고, Linux를 잘다루는 친구에게 물어봐가며 어럽게 답을 찾아 내었다.

 cat의 input output 방식의 문제이다. cat에서는 파일을 읽을때, 일정한 byte를 메모리에 읽어와서 파일에 쓰고, 그 나머지를 다시 읽어와서 파일에 쓰는 방식이다. 요쯤 되면 조금 감이 잡히는 분도 있을 것이다. 위의 예로 적용하면 test1.txt test2.txt test3.txt의 내용을 일정 byte를 메모리로 가져와서 test3.txt에 저장을 하게 된다. 그리고 다시 cat은 가져온 일정 byte이후의 내용을 확인하고 가져오려고 할것이다. test1.txt와 text2.txt의 내용은 더 이상 가져올 것이 없으므로 이대로 끝이다. 하지만 test3.txt는 다르다. 방금 test1.txt와 test2.txt의 내용이 써졌기 때문에 처음에 가져왔던 byte(파일이 새로 만들어지기 때문에 0byte) 이후의 내용이 존재한다. 그래서 이를 가져와서 다시 test3.txt에 쓰게 된다. 그러면 또 다시 test3.txt의 내용이 늘어나고 이전에 썻던 byte이후의 내용이 존재하여 이를 계속 반복하게 된다.
 cat이 한꺼번에 모든 파일의 내용을 읽어 올 수 없기 때문에, 일정 byte씩 읽어 와서 일어나는 현상이다.

 그리고 참고로, 위에서도 잠깐 언급했지만 일반적인 '>' 의 리다이렉션은 항상 결과 파일을 새로 생성한다. 그리고 그 생성하는 타이밍은 파일을 읽어서 메모리에 올리기전 가장 먼저 수행된다.
 이를 확인 할수 있는 예로
 test1.txt에 "test1.txt 파일입니다" 라는 내용이 있다고 해도,
 
$cat test1.txt > test1.txt

위와 같이 수행하면 test1.txt의 내용이 사라진다. test1.txt의 내용이 메모리에 올라가기 전에 test1.txt의 파일이 새로 생성되기 때문에 파일은 비어져 버리고 이를 test1.txt에 쓰게 되기 때문에 비어지게 된다.

위 두가지의 cat의 특성만 알더라도 사용하는데 좀더 도움이 되지 않을까 싶다.


신고

댓글

댓글쓰기 폼

2013 이전/일단까고보자

[일단까고보자] 네이트 모바일앱

hagulu 하구루2017.02.25 16:42

평소 뉴스 기사를 볼때 네이트 앱을 많이 사용한다. 시사, 스포츠, 연예 세개의 카테고리로 각각의 뉴스에 순위를 매겨서 보여준다. 일단 이슈가 되는 뉴스를 쉽게 한 눈에 볼 수 있기 때문에 많이 사용하게 된다. 그리고 베스트 리플이 잘 정리 되있어서 재치있는 리플을 쉽게 불 수 있다. 가끔 기사내용은 읽지 않고 베플만 보는 경우도 많다. 그리고 여자친구의 영향으로 가끔 톡이라는 것을 심심할때 보게 되는데 이것을 볼 때도 사용하게 된다. 출 퇴근 시간에 항상 보는 사용 빈도가 높은 앱 중의 하나이다.

 로딩도 길지 않고 사용성도 좋아서 앱 기능 자체를 깔 생각은 크게 없다. 너무 웹 뷰에 의존적이긴 하지만 사용하는데는 크게 문제될것은 없다.
 
 문제는 이들의 광고 행태이다. 다른 포털 사이트 앱과 달리 광고가 있는것 자체도 마음에 들지 않지만, 요즘 네이트(sk컴즈)의 상황을 보면 어느 정도 이해는 해줄 수 있다. 본인도 개발자로써, 뭐 돈은 벌어야 할테니. 하지만 광고를 올리는 방법이 너무 양아치같다.
 

 .       





 위 캡쳐 화면에서 보는 것처럼 메뉴 버튼을 가리도록 광고가 나온다. 앱을 구동했을때, 광고가 잠시 올로왔다가 사라지는 방식이다. 광고가 가리고 있는 시간이 꽤 될 뿐더러, 앱을 구동하고 바로 자리를 잡고 있는 것이 아니라, 화면이 다 나온 뒤 잠시 후에 올라 온다. 사용자는 앱을 구통하고, 무심결에 다른 버튼을 누르려고 하다보면, 광고가 올라와서 의도치 않게 광고를 누르는 경우가 많다. 광고주, 사용자는 원치 않는 광고 관리자만 배부른 전형적인 무효 클릭이다. 게다가 이들이 올리는 광고는 sk에서 운영하는 T-ad라는 광고 회사에서 진행하는 것이다.  결국 지내들 배불리기 위해서, 광고 주와 사용자를 우롱하는 것이다.
 더 웃긴건 T-ad가 이를 올린 다른 클라이언트 들에게 하는 처사이다.
 T-ad가 갓 서비스를 시작한 베타 시절 회자의 앱을 만드는데 적용을 해본 적이 있다. 우리는 광고를 앱 가장 상당에 올려 놓았다. 그리고 가끔 버튼이 광고 바로 밑에 보여지는 경우가 있다. 흔히 있는 일이기 때문에 별 신경을 쓰지 않았다 그런데, 광고 클릭이 좀 늘어나자, T-ad측에서 클릭을 유도하는 UI이므로 UI를 변경해 달라고 요청이 왔다. 버튼이 광고 주변에 있다는 이유였다. 광고가 버튼을 가렸다 사라지는 것이 아니라 그저 광고 밑에 버튼이 있다는 이유에서이다. 이렇게 다른 클라이언트 들에게는 까탈스럽게 굴더니, 자기네 앱에는 유도가 아니라 거의 낚시질을 하도록 광고를 올려 놓았다.

 현재 국내 포털은 네이버가 잠식하다 싶이하고, 다음이 그 다음으로 어느정도 포지션을 잡고있다. 네이트는 사활의 기로에 놓여 있는 것으로 알고 있다. 또한 최근 paran과 야후 코리아가 운영에 한계를 느끼고 웹 포털 서비스를 모두 접어 버렸다. 네이트도 이를 남일 같이 않게 지켜 봤을 것이다.
 이러한 시점에서 이렇게 광고 수익 좀 벌자고 사용자와 광고주를 기만하는 기획은 누구 머리에서 나온 것일까?

포털은 사용자의 이용도에 따라서 가치가 평가 된다. 이런식으로 사용자를 기만 한다면, 이러한 포털에 이용도가 높아질 수 있을까? 작은 것 부터 하나하나 고쳐 나가서 다시 예전의 명성을 얻었으면 하는 바램에서 몇자 끄적여 보았다.

이건 정말 아닌것 같다.


신고

댓글

댓글쓰기 폼

2013 이전/기타

옛날 웹페이지를 찾아 보자!

hagulu 하구루2017.02.25 16:40

인터넷을 예전 모뎀시절 부터 사용해 왔다면, 예전 hanmail, empas 등의 예전 웹페이지들이 그리울때가 있을 것이다. 또는 자료 수집이나 참고용으로 예전 90년대 후반 2000년대 초반의 웹페이지가 필요할 때가 있을 수 있다.

 혹은. 백업 해놓지 않았었던, 웹 페이지 관련 리소스를 날려 버렸을때, 기존 웹 페이지가 어딘가 보관되어 있다면, 필요한 리소스들을 얻어 낼 수 있을것이다.(본인 체험)
 
 놀랍게도 이를 저장해 놓고 기록하는 곳이 있다. 도메인을 연결만 해놓은 것이 아니라, 리소스를 저장하고 이를 기록해 놓고 있다. 무려 1996년 이후부터 기록이 되어 보관중이다. 웹 페이지 설명에서는 무려 240 billion(2400억)의 페이지가 보관되어 있다고 한다.

이곳이다. 유명한 몇몇 사이트 뿐만 보관하는 것이 아니다. 본인이 2000년도 초반 학창시절에 재미로 만들었던, 추억의 hihome 홈페이지도 보관이 되어 있다. 예전에 만들었다가 보관해놓지 못했던 페이지가 있다면, 한번 재미삼아 찾아보는것도 좋을 것 같다. 찾는다면, 그때의 추억이 새록새록 떠오를 것이다.

사용법은 간단하다.



페이지에 접속하여 위 사진에 표시된 부분에 주소를 입력하면 다음 화면 처럼 수집된 기록과 함께  표시되고 수집된 날짜를 선택하면 그때의 페이지를 볼수가 있다.







국내 인터넷 초창기에 가장 많이 사용되었던 야후 코리아 페이지 이다.



무려 구글의 베타 시절 모습도 볼수 있다.




다음의 모태가 되었던 한메일의 모습이다.



네이버의 초창기 모습도 볼수있다.

일부 소실되거나 제대로 나오지 않는 리소스들도 있지만, 그때 페이지를 기억하는데는 크게 문제가 없는 수준이다.  지금 보기에는 촌스럽고 텍스트 위주였지만, 그때 당시에는 너무나도 신기하고 놀라운 세상이었다. 여러분들이 기억하는 페이지를 통해서 시간여행을 해보는 것도 재미있을것 같다.


신고

댓글

댓글쓰기 폼

2013 이전/node.js

[node.js] Socket.io 맛보기 (웹 채팅 만들기)

hagulu 하구루2017.02.25 16:34

node.js 가 나타나면서 가장 주목 받았던 모듈중에 하나였던 Socket.io를 소개 해보려고 한다.

 
 웹을 통한 애플리케이션을 개발할때 가장 힘든점이, 바로 실시간 데이터 적용이다. 서버에서 넘어온 정보를 실시간 으로 화면에 보여 주어야 하는데 refresh를 이용하면 화면이 깜박이는 문제가 있다. 이를 위한 대안으로 Ajax를 많이 사용하게 된다. 하지만 이것은 Client위주의 개발에 적합하다. 서버에 변화 된 내용을 항상 유지하려면 poliing을 직접 구현해야 하는데 여간 번거로운 일이 아닐수 없다.
 이를 보완하기 위해 등장한것이 바로 WebSocket이다. 일반 애플리케이션에서 사용하면 Socket을 브라우져에서 사용가능하게 한 것으로, 어렵지 않게 웹상에서 Socket과 같은 방식의 애플리케이션 구현이 가능하다. 하지만 아직 표준이 정해지지 않았고, 이를 호환하는 브라우져가 제한적이다. 그리고 보안에 대한 논란도 아직 진행중이다.




  WebSocket 지원 여부(이미지 출처: http://caniuse.com)

 표에 보는 것처럼 전체의 55%정도만 완벽하게 지원이되고 부분적인 지원이 5%정도이다. 그리고 국내에서 가장 많이 사용하는 IE에서는 10.0에서나 지원이 가능하다. 
 
 이에 대한 대안이 바로 Socket.io이다. 서버는 node.js의 모듈로 간단히 이용이 가능하고 client도 모듈에 포함된 javascript 파일 하나만 있으면 지원이 된다. 일반 javascript를 사용하기 때문에 호환 문제도 걱정이 없다.
 
 더 길게 끌지 않고 예제를 통해서 살펴 보도록 하겠다.
 소켓 통신을 이용할때 가장 만만한 예제가 채팅이므로 이를 만드는 예제를 보도록 하겠다.
node.js와 socket.io 모듈의 설치에 관해서는 아래 두 포스팅을 참고하기 바란다.
[node.js] npm을 이용한 module 설치

Socket.io는 기본적인 웹서버 모듈과 연동하게 된다.
여기에서는 단순하게 http 모듈을 이용해서 소개해 보겠다.
var app = require('http').createServer(handler)
	, io = require('socket.io').listen(app)
	, fs = require('fs')
  
    app.listen(8005);
  
function handler (req, res) {
    fs.readFile(__dirname + '/index.html',
    function (err, data) {
        if (err) {
        	res.writeHead(500);
        	return res.end('Error loading index.html');
       	}
  
       	res.writeHead(200);
       	res.end(data);
    });
}
  
io.sockets.on('connection', function (socket) {
      socket.on('my other event', function (data) {
         	console.log(data);
        	socket.emit("my_message", data);
        	socket.broadcast.emit("message", data);
       });
 });
 handler 부분은 http를 위한 부분이니 다음에 다루어 보도록 하겠다.
 중요한 부분은 아래 소켓 관련된 부분이다.
 일반 프로그래밍에서 소켓을 통한 개발을 해보았다면 어렵지 않게 이해가 가능 할것으로 보인다.
 2번째 라인에 require 부분에서 app 즉, http서버를 통해서 socket을 listen을 하게 된다.
 그리고 20번째 라인에서 Client가 연결이 되었을떄의 작업을 function을 통해 정의 해주게 된다. 보는 것처럼 연결이 되었을때 생성된 해당 socket은 파라미터로 가져다 쓸 수가 있다. 이 소켓을 통해 연결된 Client와 통신하게 된다.
 여기에서 다시 해당 소켓에 새로운 이벤트를 추가해주게 된다. 해당 소켓에 on 함수를 통해 새로운 이벤트를 추가를 해주면 된다. 위 소스에서는 "my other event" 라는 이벤트를 추가하고 해당 이벤트가 발생했을때, 이루어질 작업을 function을 통해서 등록 해주게 된다. 이벤트와 함께 들어온 data는 파라미터를 통해 이용할 수 있다.
 23번째 라인은 들어 온 데이터를 다시 Client로  "my_message" 라는 이벤트로 전송하는 것이다. 이쯤 되면 감이 올것이다. 이벤트를 생성하여 발생시키는 것은 emit라는 메소드를 이용하면 된다. 잠시후 client에서도 보겠지만 같은 함수를 사용한다. 일반적으로 socket에 내장되어 있는 함수로 해당 소켓으로만 이벤트를 발생 시키는 것이다. 하지만 여기서 해보려는것은 채팅이다. 채팅의 경우 자기 자신만이 아니라 모두에게 전송이 이루어 져야 한다.
 이를 구현한것이 바로 24번째 라인이다. socket에 broadcast의 emit를 통해서 이벤트를 발생시키면, 해당 소켓이 연결된 Client를 제외한 다른 소켓으로 다른 모든 Client들에게 이벤트를 발생시키게 된다.
 이러면 자연스럽게 채팅과 같은 기능을 하는 서버가 완성이 된 것이다.
 정말 간단하기 그지 없다.
 이어서 바로 Client부분을 보겠다.
 먼저 아래 파일은 위 소스에서 구현한 javascript 파일과 같은 디렉토리에 index.html에 작성하면된다. 그 이유는 위 소스의 handler의 설정에 따른것 이다. 필요하다면 이를 수정해서 다른 디렉토리나 파일로 이용하는 것도 가능하다.
 

Client에서는 조심해야할 부분이 많다.
 먼저 조심해야할 부분이 1라인의 src부분이다. 내 디렉토리에는 눈씻고 찾아 봐도 /socket.io/socket.io.js 파일이 없는데, 왜 그래도 해야 할까 싶지만, 이것은 서버에 있는 socket.io 모듈이 알아서 연결해 주는 부분이다. 그러므로 의심 하지 말고 이용하기 바란다. 혹시 다른 곳에서 구하거나, 다른 곳의 링크를 이용할 경우 socket.io와 socket.io.js의 버젼이 맞지 않아서 문제가 발생할 수도 있으니 꼭 위와 같은 방식으로 이용하기 바란다.
 5번째 라인에서 소켓을 연결하게 된다. 간단하게 소켓을 생성하고 바로 연결이 된다. 예전 버젼에서는 번거롭게 진행해야 하니 최신버젼을 꼭사용하기 바란다. 본인은 원격지 서버로 이용하고, 포트 설정떄문에 포트를 다르게 했지만, local에서 테스트 할경우 "http://localhost" 형식으로 해주기만 하면된다.
 이제 서버에서 올라오게될 이벤트를 등록해주는 부분이 6~13라인이다. 보는 것처럼 서버와 문법이 똑같다. node.js의 장점이 바로 이런것이다. 서버에서 작성한 문법 그대로 웹 클라이언트에서 구현해주면 된다. 위에서는 24라인에 있는 div에 새로온 메시지와 현제 메시지를 합쳐 주는 일을 한다. "message"는 다른 곳에서 온 메시지를 처리하는 것이고, "my_message"는 내 메시지가 서버를 거쳐서 다시 오게되는 메시지를 처리하는 것이다. "my_message"는 굳이 서버를 거칠 필요는 없지만, 소켓의 동작을 보여주기 위해서 적용해 보았다.
 15~18라인은 메시지를 서버로 보내는 부분이다. 이 function은 아래 22 ~ 23라인에서 return키 혹은 버튼 클릭을 통해서 불려지게 된다. 이벤트 발생은 서버와 마찬가지로  emit 메소드를 통해서 사용하면 된다. 서버에 등록 해 두었던 "my other event" 로 이벤트를 발생시키도록 하였다. 메시지 내용은 아래 22번째 라인에 있는 input의 벨류로 하면된다. 17라인은 보낸 다음에 input을 비워주는 부분이다.
 
 여기까지 진행이되면 기본적인 채팅 프로그램이 간단하게 완성이 된다.
 로컬로 진행되었을경우 브라우져로 http://localhost로 접속을 하게 되고, 저 처럼 원격지로 진행된경우는 원격지 도메인을 입력하여 실행하여 보면된다.
간단하게 실행한 예이다





신고

댓글

댓글쓰기 폼

2013 이전/iOS개발

[iOS 개발] UIButton title, image 위치 정리

hagulu 하구루2017.02.25 16:32

UIButton을 사용하다 보면 title, image등을 버튼위에 올려서 사용하게 된다. 

그런데 이들이 깔끔하게 배치되지 않을때가 많다.

UIButton의 titleLabel의 frame을 직접 적용해도 변화가 없을 것이다.
그래서 대부분 포기하고 버튼 위에 따로 View를 올리는 경우가 있는데,
이럴 경우 버튼 state 마다 위에 올린 뷰를 수동으로 바꿔 주어야 한다.
특히, UIControlStateHighlighted 를 처리하려면 소스가 지저분해지고 번거러워 질 수 밖에 없다.  
다행히도 이들을 배치할 수 있는 방법은 존재한다.
일단 image, title의 Alignment를 정해줄수 있는데 아래와 같이 가능하다.
  [btn setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
    [btn setContentVerticalAlignment:UIControlContentVerticalAlignmentBottom];
각각 가로 세로의 정렬을 관리할수 있다.
해당 메소드는 UIControl에 포함된 메소드로 이를 상속 받은 UI들은 모두 사용할 수 있다.
위와 같이 배치를 하면 어느정도 원하는 모양을 가질 수 있지만, 아직 부족하다고 느낄수 있다.
좀더 세밀한 보정이 필요할때 아래와 같이 가능하다.
    [btn setContentEdgeInsets:UIEdgeInsetsMake(0, 10, 0, 0)];
    [btn setImageEdgeInsets:UIEdgeInsetsMake(0, 10, 0, 0)];
    [btn setTitleEdgeInsets:UIEdgeInsetsMake(0, 10, 0, 0)];
각각 Image와 Title의 EdgInsets을 지정해 줄 수 있는데, EdgeInsets은 각각 top, left, bottm, right 를 나타내고,
이를 통해서 위치 조정이 가능하다.
EdgeInsets의 자세한 내용은 해당 링크를 참조하기 바란다.

그리고 두개를 모두 같이 보정하고 싶을때는, contentEdgeInsets를 조정해 주면 된다.

이를 이용하면 버튼을 휠씬 간편하고 깔끔하게 관리 할 수 있게 된다.
간단하지만, 모르고 넘어가서 고생을 할 수있는 부분이다.
이것 때문에 지저분해진 소스가 있다면 지금 바로 수정해 보기 바란다.


신고

댓글

댓글쓰기 폼

2013 이전/iOS개발

[iPad 개발] PopoverController contentSize 문제

hagulu 하구루2017.02.25 16:32

PopoverController 를 사용하다보면 사이즈 때문에 골머리를 썩을 경우가 많을 것이다.

일단 가장 평범한 방법은 해당 PopoverController에 들어갈 해당 UIViewController에
- (CGSize)contentSizeForViewInPopover {
    return CGSizeMake(320, 480);
}
위 처럼 해당 하는 함수를 override 해주면 리턴하는 사이즈로 PopoverController 사이즈를 조절 해준다.
하지만 여기도 문제점이 하나 있다.
navigationController를 사용할때 push나 pop을 하게 되면 늘어나기는 하지만 줄어 들지는 않는다.
구글링을 통해서 얻게된 방법인데, 일종의 꼼수라고 볼수 있겠다.
- (void) forcePopoverSize 
{
    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, 
                                          currentSetSizeForPopover.height - 1.0f);
    self.contentSizeForViewInPopover = fakeMomentarySize;
}


- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self forcePopoverSize];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    self.contentSizeForViewInPopover = currentSetSizeForPopover;
}

위 처럼 ViewController에 해당하는 함수에 위 내용을 추가만 해주면 된다.
모두 ViewController 멤버를 사용하는 것이니, 바로 가져다 붙여 써도 잘 적용될것이다.
해당 메소드 이름을 정확히 확인하고 적용 바란다.
처음에 잘못 보고 적용을 해서 삽질을 했엇다. ㅠㅠ

각 viewController에 위사항을 적용하면, 언제 그랫냐는 듯이 pop, push 간에 PopoverController크기가 늘었다 줄었다 한다.

하지만 여기도 문제는 있다.
ViewController 사이의 사이즈 크기가 차이가 많이 나면 정신없이 움직여서 산만한 느낌이 든다.
이 기능이 꼼수를 통해서만 이루어 지는걸 봐서는 정신 없게 움직이는것을 방지하기 위해 그렇지 않을까 싶다.

때문에, 이 소스의 적용은 상황에 따라 잘 적용해야 할 것이다.


신고

댓글

댓글쓰기 폼

2013 이전/iOS개발

[iOS 개발] 안정적이고 flexible 한 UITableViewCell UI 구현하기

hagulu 하구루2017.02.25 16:31

UITableView 를 이용할때 Cell을 Customize 하여 사용하는 경우가 많을 것이다.

 이렇게 사용할때  Cell의 크기에 따라 Cell의 구성요소의 위치와 크기가 다르게 구성하는 경우가 많을 것이다.
 하지만 각각의 Cell을 UI사이즈나 위치가 변경할때 마다 각각의 Cell의 위치나 크기를 매번 새로 적용해주게 되면 여러 문제가 발생할 수가 있다.
 이때, 해당 Cell의 frame만 가지고 구성요소의 위치를 지정해 주게 되면 여러 문제에 봉착하게 된다.

 그래서 Cell을 구성할떄 위치와 크기에 변화가 필요한 것들은 모두  각 UIView에 AutoresizingMask를 적용하여 사용해야 한다. 전체 View가 유기적으로 AutoresizingMask를 적용하지 않아서 전체 적으로 static하게 구성하더라도, Cell은 적어도 AutoresizingMask를 통해서 구성해야 한다.
 Cell의 frame을 이용해서 계산하여 UIView의 위치를 배치하면, 최초 구동시나, 회전하여 구동할때 등 문제가 발생하게 된다.

 그리고 한가지 더 중요한 점이 Cell에서 구성되는 UIView를 Cell의 self에 바로 addSubview하는 경우가 많은데, 꼭! self.contentView에 addSubview 를 해주는 것이 좋다. Grouped UITableView에서 는 cell안에 표시되려면 꼭 필요한 부분이고, Plain이라고 하더라도 적용해 주어야한다. 그렇지 않으면 AutoresizingMask하는 부분이 의도한 대로 진행되지 않을 것이다. 따라서 특정한 경우가 아니라면 꼭 contentView에 addSubview를 해주어야 한다.
 어찌보면 당연한 것이지만, 쉽게 생각하고 무시하고 진행하는 경우가 있기때문에, 이 두 부분은 꼭 기억하고 UIView를 관리 하기 바란다.


신고

댓글

댓글쓰기 폼

hagulu.com

.....

VISITED

Today : 103

Total : 119,814

Lately Comment